• CF1406E


    题目

    交互题,你有一个({1,...,n})的集合,你想要找出其中一个数(x),有3个操作:

    • A a:询问当前集合中有多少元素是(a)的倍数。
    • B a:询问当前集合中有多少元素是(a)的倍数,然后从集合中将(a)的倍数的数全部删去,除了(x)(x)永远不会被删除,即使它是(a)的倍数。注意这个操作要求(a>1)
    • C a:代表你找到了(x)(x=a)。结束。

    你最多可以执行操作(10000)次,(nle 100000)

    题解

    很自然就想到要枚举质数去询问。(10^5)以内质数个数为(9592)。假设可以通过询问一轮知道(x)包含的质因子为(p_1,p_2,...,p_k),那么就可以枚举质因子的幂次进行询问,得到真正的(x),这一步最多只需要不到20次操作。

    如何得到(x)包含的质因子?从小到大枚举质数进行B询问,假设当前枚举到(p_{i+1}),已经知道(x)包含(p_1,p_2,...,p_i),那么(x)包含(p_{i+1})的条件就是操作“B (p_1p_2...p_{i+1})”返回的结果为1。这一步最多需要(9592)次操作。那么关键就是如何知道(x)包含的第一个(p_1)

    用分块的思想,每(T)次B操作后执行一次“A 1”,判断集合中剩余个数是否多1,如果是说明这段区间内的存在质数为(x)的质因子。然后遍历这段的质数挨个检查即可。当获得大于等于1个质数后,就可以用上面的方法找出剩余的质因子,故最多就只需遍历一个(T)次。这步最多需要(frac{9592}{T}+T)次操作,取(T=sqrt{9592}=98),即最多(196)次操作。

    故总的最多操作为(196+9592+20+1=9809<10000)

    #include <bits/stdc++.h>
    
    // #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    #define mp make_pair
    #define seteps(N) fixed << setprecision(N) 
    typedef long long ll;
    
    using namespace std;
    /*-----------------------------------------------------------------*/
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    #define INF 0x3f3f3f3f
    
    const int N = 1e5 + 1;
    const double eps = 1e-5;
    
    
    
    bool vis[N], isnp[N];
    int pri[N], cnt;
    vector<int> d;
    int ret = 0;
    
    int del(int p, int n) {
    	int res = 0;
    	for(int i = p; i <= n; i += p) {
    		if(!vis[i]) {
    			res++;
    			vis[i] = 1;
    		}
    	}
    	return res;
    }
    
    int n;
    int main() {
        // IOS;
    	for(int i = 2; i < N; i++) {
    		if(!isnp[i]) {
    			pri[cnt++] = i;
    		}
    		for(int j = 0; j < cnt && i * pri[j] < N; j++) {
    			isnp[i * pri[j]] = 1;
    			if(i % pri[j] == 0) {
    				break;
    			}
    		}
    	}
    	cin >> n;
    	int m = 0;
    	for(int i = 0; i < cnt; i++) {
    		m++;
    		if(pri[i] > n) {
    			break;
    		}
    	}
    	int sq = sqrt(m), pre = 0;
    	ll k = 1;
    	int ret = n;
    	for(int i = 0; i < m && k * pri[i] <= n; i++) {
    		int tnum, num;
    		cout << "B " << k * pri[i] << endl;
    		cin >> tnum;
    		num = del(k * pri[i], n);
    		ret -= num;	
    		if(!d.empty()) {
    			if(num != tnum) {
    				d.push_back(pri[i]);
    				k *= pri[i];
    			}
    		} else if((i - pre + 1) % sq == 0 || i == m - 1) {
    			int r;
    			cout << "A 1" << endl;
    			cin >> r;
    			if(ret != r) {
    				for(int j = pre; j <= i; j++) {
    					int flag;
    					cout << "A " << pri[j] << endl;
    					cin >> flag;
    					if(flag) {
    						d.push_back(pri[j]);
    						k *= pri[j];
    					}
    				}
    			}
    			pre = i + 1;
    		}
    	}
    	for(int i = 0; i < d.size() && k <= n; i++) {
    		ll pw = d[i];
    		while(k * pw <= n) {
    			int flag;
    			cout << "A " << k * pw << endl;
    			cin >> flag;
    			if(!flag) {
    				k = k * (pw / d[i]);
    				break;
    			}
    			pw *= d[i];
    			if(k * pw > n) {
    				k = k * (pw / d[i]);
    				break;
    			}
    		}
    	}
    	cout << "C " << k << endl;
    }
    
  • 相关阅读:
    Java实现2048小游戏
    归并排序【代码】
    插入排序【代码】
    选择排序【代码】
    考试系统
    九九乘法表
    万年历
    猜数游戏
    C++知识点(杂)
    Core Data ,inverse
  • 原文地址:https://www.cnblogs.com/limil/p/15258325.html
Copyright © 2020-2023  润新知