CF题目泛做 3

goodbye 2020,hello 2021

泛做1 泛做2

[x] CF1355F

一道有意思的交互题。

简单思考后发现超过 $\sqrt{10^9}$ 的质数我们不需要考虑他们的存在,只要让答案乘二即可。

而对于 $\leq \sqrt{10^9}$ 的质数,我们每次询问 $\prod_i p_i$ ,$p_i$ 表示一个质数,我们就可以知道 $X$ 中是否存在这个质数。

而对于一个 $\leq 10^9$ 的数,最多可以包含 $9$ 个质因子,那么我们最多需要 $5$ 次操作就可以问出 $X$ 中质数的幂。

但是注意到 $\sqrt{10^9}$ 太多了,而很容易发现其实只需要保留 $\leq \sqrt[3]{10^9}$ 即可,因为我们允许的是最多剩下两个质数,只需输出 $2\times Ans$ 即可,因为最后答有可能是 $Ans,2\times Ans,3\times Ans,4\times Ans$ ,无论取哪个都符合条件。

则我们将值域缩到了 $1000$ ,交互次数还达不到 $22$ 次,然后就不会了。。。

可以发现我们少用了一个条件,$|Ans-real|\leq 7$ 。 不难想到我们的值域还可以在减少一点!

我们将上述情况进行推导,我们设已知的质数乘积为 $x$ ,则当我们扫描的质数 $p$ 满足 $x\cdot p^3>10^9$ 就可以停止。

如果说 $x\geq 4$ 时,我们只需要扫描 $\leq \sqrt[3]{\frac{10^9}{4}}$ 的质数,交互次数为 $21$ 次,符合条件。

否则,当扫描前面的质数 $x<4$ 时,那么我们最多答案为 $16$ ,最小为 $1$ ,只需要输出 $8$ 即可。

那么我们只需要将 $2\cdot Ans$ 与 $8$ 做比较,扫描前 $\leq \sqrt[3]{\frac{10^9}{4}}$ 即可解决问题。

上限 $21$ 次即可解决问题,还是在将质数从小到大直接分组的情况下,应该还是有优化的空间的。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<climits>
#define int long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=1e5+11;
const int INF1=1e18;
const int INF2=1e9;
int v[MAXN],pri[MAXN];
void init(){
    for(int i=2;i<MAXN;i++){
        if(!v[i]) pri[++pri[0]]=i,v[i]=i;
        for(int j=1;pri[j]<MAXN/i;j++){
            v[pri[j]*i]=pri[j]; if(!(i%pri[j])) break;
        }
    }return;
}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int ask(int x){printf("? %lld\n",x);fflush(stdout);return read();}
void tell(int x){printf("! %lld\n",x);fflush(stdout);return;}
vector<int> vec[21],ANS; int cnt,G[21];
signed main(){
    init(); pri[0]=114; cnt=1; G[1]=1;
    for(int i=1;i<=pri[0];i++){
        if(G[cnt]<=INF1/pri[i]){vec[cnt].pb(pri[i]);G[cnt]*=pri[i];continue;}
        ++cnt; vec[cnt].pb(pri[i]),G[cnt]=pri[i];
    }
    int cas=read();while(cas--){
        int Ans=1; ANS.clear();
        for(int i=1;i<=cnt;i++){
            int P=ask(G[i]); for(auto v:vec[i]) if(!(P%v)) ANS.pb(v);
        }
        for(int j=0;j+1<ANS.size();j+=2){
            int p=ANS[j],q=ANS[j+1],r1=1,r2=1;
            while(r1<=INF2/p) r1*=p; while(r2<=INF2/q) r2*=q;
            int R=ask(r1*r2),c1=0,c2=0;
            while(!(R%p)) c1++,R/=p; while(!(R%q)) c2++,R/=q;
            Ans=Ans*(c1+1)*(c2+1);
        }
        if(ANS.size()&1){
            int p=ANS[ANS.size()-1],r=1; while(r<=INF2/p) r*=p;
            int R=ask(r),c=0; while(!(R%p)) c++,R/=p;
            Ans=Ans*(c+1);
        }
        tell(max(8ll,Ans*2));
    }
}
 
View Code

[] CF1474E

我们发现一次交换肯定会让一个位置归位,而且最优的操作数肯定为 $n-1$ ,否则可以找到一个 $a_i=i$ 的位置交换即可。

则我们考虑倒推,可以发现最优情况肯定是 $\sum_{i=1}^{n-1} (\max\{i-1,n-i\})^2$ ,而上界也很好构造,因为我们的交换是可以有逆操作的。

即若 $swap(x,y)$ ,等价于反操作 $swap'(x,y)$ 。 时间复杂度 $O(n)$ 。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<climits>
#include<algorithm>
#include<queue>
#include<vector>
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define int long long
using namespace std;
inline int read(){
    int f=1,ans=0; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=1e5+11;
int T,N,A[MAXN],Ans,P[MAXN]; vector<int> vec;
signed main(){
    T=read();
    while(T--){
        vec.clear(),Ans=0;;
        N=read(); for(int i=1;i<=N;i++) A[i]=i;
        vec.pb(N); Ans+=(N-1)*(N-1); swap(A[1],A[N]);
        for(int i=2;i<N;i++){
            int d1=i-1,d2=N-i; vec.pb(i);
            if(d1>=d2) Ans+=d1*d1,swap(A[1],A[i]);
            else Ans+=d2*d2,swap(A[i],A[N]);
        }
        for(int i=1;i<=N;i++) P[A[i]]=i;
        printf("%lld\n",Ans);
        for(int i=1;i<=N;i++) printf("%lld ",A[i]); printf("\n");
        printf("%lld\n",N-1);
        for(int i=N-1;i>=1;i--){
            int s=P[i]; printf("%lld %lld\n",i,P[i]);
            int x=P[i],y=i; swap(A[x],A[y]); P[A[x]]=x,P[A[y]]=y;
        }
    }
    return 0;
}
View Code

 

posted @ 2021-01-01 00:01  siruiyang_sry  阅读(121)  评论(0编辑  收藏  举报