zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    巴洛克式和哥特式的区别
    推荐阅读书籍,是时候再行动起来了。
    AtCoder ABC 159F Knapsack for All Segments
    AtCoder ABC 159E Dividing Chocolate
    AtCoder ABC 158F Removing Robots
    AtCoder ABC 158E Divisible Substring
    AtCoder ABC 157F Yakiniku Optimization Problem
    AtCoder ABC 157E Simple String Queries
    AtCoder ABC 157D Friend Suggestions
    AtCoder ABC 156F Modularness
  • 原文地址:https://www.cnblogs.com/limil/p/15258325.html
Copyright © 2011-2022 走看看