天天看点

2020 Jiangsu Collegiate Programming Contest D Delete Prime --分块+二分

2020 Jiangsu Collegiate Programming Contest

题目描述

有 n 个球排成一行。每个球上都有一个数字,第i个球上的数字是i (1 ≤ i ≤ n). 。

对于每一轮,我们选择索引为1或素数的球,并将它们从列表中踢出按顺序排队。在那之后,我们开始下一轮的比赛,剩下的球保持相对位置不会改变,其索引从1开始按顺序重新标记(但球上的数字不会改变)。我们重复这个过程,直到没有球留下。

有一个踢出序列D,初始为空,从一开始。每次球被踢出时,球上的数字都会被加到D后面。

例如,当n=6时,球[1,2,3,4,5,6]在一条直线上。在第一轮,我们踢出了球[1,2,3,5](索引1,2,3,5)按顺序排列,其余的球为[4,6]。在第二轮,我们踢出局[4,6](索引1,2)按顺序排列,没有剩余的球。所以被踢出的序列是D=[1,2,3,5,4,6]。注D的索引总是从1开始。

2020 Jiangsu Collegiate Programming Contest D Delete Prime --分块+二分

现在您需要回答两类问题:

•类型1给定n和k,踢出序列中k的指数是多少?换言之,找到这样的xD[x]=k。

•类型2给定n和k,踢出序列中的第k个数字是多少?换句话说,找到x使得D[k]=x。

输入

输入的第一行包含一个整数 T ( 1 ≤ T ≤ 2 ⋅ 1 0 5 ) T(1≤ T≤ 2 · 10^5) T(1≤T≤2⋅105),表示查询的数量。

对于下面的T行,每行包含三个整数 T , n , k ( T ∈ { 1 , 2 } , 1 ≤ K ≤ N ≤ 1 0 6 ) T,n,k(T∈ \{1, 2\}, 1 ≤ K≤ N≤ 10^6) T,n,k(T∈{1,2},1≤K≤N≤106),代表上面提到的类型为t的查询。

输出

对于每个查询,在一行中输出答案

#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
template<class...Args>
void debug(Args... args) {//Parameter pack
    auto tmp = { (cout << args << ' ', 0)... };
    cout << "\n";
}
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
typedef pair<int, int>pii;
const ll N = 1e6 + 5;
const ll MOD = 998244353;
const ll INF = 1e9 + 7;

ll primes[N], cnt;
bool st[N];
void get_primes(ll n) {
    for (ll i = 2; i <= n; i++) {
        if (!st[i]) primes[cnt++] = i;
        for (ll j = 0; primes[j] <= n / i; j++) {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}
vector<int>d[N];
int vis[N];
int cntd;
void get_D(int n) {
    memset(vis, 0, sizeof(vis));
    int viscnt = 0;
    int pos;
    while (viscnt < n) {
        pos = 0;
        for (int i = 1; i <= n; i++) {
            if (!vis[i]) {
                pos++;
                if (!st[pos]) {
                    vis[i] = 1;
                    viscnt++;
                    d[cntd].push_back(i);
                }
            }
        }
        cntd++;
    }
}
int get_rank(int n, int k) {
    int ans = 0;
    for (int i = 0; i < cntd; i++) {
        int t = upper_bound(d[i].begin(), d[i].end(), k) - d[i].begin() - 1;
        if (d[i][t] == k) {
            ans += t;
            return ans + 1;
        }
        else ans += upper_bound(d[i].begin(), d[i].end(), n) - d[i].begin();
    }
}
int get_val(int n,int k) {
    int ans = 0;
    for (int i = 0; i < cntd; i++) {
        int t = upper_bound(d[i].begin(), d[i].end(), n) - d[i].begin();
        if (k - t <= 0) return d[i][k-1];
        else k -= t;
    }
}
int main() {
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    
    get_primes(N);
    get_D(1000002);
    int t;
    cin >> t;
    while (t--) {
        int opt, n, k;
        cin >> opt >> n >> k;
        if (opt == 1)cout << get_rank(n, k) << "\n";
        else cout << get_val(n, k) << "\n";
    }
    return 0;
}

           

继续阅读