• CF1406E Deleting Numbers 题解


    Codeforces
    Luogu

    Description.

    交互,初始有一个集合 \(S=\{1,2,\cdots,n\}\),你需要询问一个数 \(x\)
    你可以进行三种询问:

    1. 问有多少个数是 \(a\) 的倍数
    2. 问有多少个数是 \(a\) 的倍数,并把 \(a\) 倍数删除,\(x\) 无法被删除
    3. 回答你找到了 \(x\)

    \(n\le 10^5,\text{limit}\le 10000\)

    Solution.

    首先肯定大质数、小质数分别处理。
    小质数肯定可以随便处理,因为总个数不超过 \(\mathcal O(\sqrt n)\)
    就直接先消,然后枚举指数。

    主要是大质数怎么处理。
    如果有小质数,那每个大质数 \(a\) 的倍数除了 \(a\)\(x\) 其他都被消了。
    所以可以 \(1\) 次判断是否存在 \(a|x\)
    如果没有小质数,相当于答案是个质数,此时我们无法按照之前的方法判断。
    有个朴素的想法是删一次问一次,这样是 \(O(2n)\) 的,无法通过。
    考虑分块,对整块问一次,如果有再继续问,这样就变成 \(O(n+2\sqrt n)\) 了。

    Coding.

    点击查看代码
    //Coded by Kamiyama_Shiki on 2021.11.15 {{{
    //是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了
    #include<bits/stdc++.h>
    #define debug(...) fprintf(stderr,__VA_ARGS__)
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
    const int N=100005;int n;
    const int V=N;int pr[V],pc,ls[V];char pv[V];//prinit{{{
    inline void prinit(int n=V-1)
    {
    	pv[1]=1,ls[1]=0;for(int i=1;i<=n;i++)
    	{
    		if(!pv[i]) pr[++pc]=i,ls[i]=i;
    		for(int j=1;j<=pc&&i*pr[j]<=n;j++) {pv[i*pr[j]]=1;if(i%pr[j]==0) break;}
    	}
    }//}}}
    inline int A(int x)
    {
    	if(x>n) return 0;
    	printf("A %d\n",x),fflush(stdout);
    	int w;return read(w),w;
    }
    inline int B(int x)
    {
    	if(x>n) return 0;
    	printf("B %d\n",x),fflush(stdout);
    	int w;return read(w),w;
    }
    inline void C(int x) {printf("C %d\n",x),fflush(stdout);}
    int main()
    {
    	int rs=1,wh=1;read(n),prinit(n);
    	for(int i=1;i<=pc&&pr[i]*pr[i]<=n;i++)
    	{
    		int x=pr[i],nw=0;B(pr[i]),nw=A(pr[i]);
    		wh=i+1;while(nw) rs*=pr[i],nw=A(x*=pr[i]);
    	}
    	if(rs!=1)
    	{
    		for(int i=wh;i<=pc;i++) if(A(pr[i])>1) return C(pr[i]*rs),0;
    		return C(rs),0;
    	}
    	for(int l=wh,r=l+99,now=A(1),nx;l<=pc;l+=100,r+=100,now=nx)
    	{
    		for(int i=l;i<=r&&i<=pc;i++) B(pr[i]);
    		nx=A(1);if(now==nx+min(r,pc)-l+1) continue;
    		for(int i=l;i<=r&&i<=pc;i++) if(A(pr[i])) return C(pr[i]),0;
    	}return C(1),0;
    }
    
  • 相关阅读:
    COM编程-注册DLL形式的COM服务器
    控制台console使用MFC库函数,Cout输出CString的方法
    [C#]窗体切换--避免开启多个线程
    OpenCV配置使用版
    Dependency Walker使用说明
    TCP粘包和半包的处理方法
    GENERATED_UCLASS_BODY 和 GENERATED_BODY 区别
    c++ 的 坑真多之头文件
    Introduction to replication 翻译
    c++ 的 static_cast
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15559418.html
Copyright © 2020-2023  润新知