天天看點

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;
}

           

繼續閱讀