noip模擬9
阿新 • • 發佈:2021-06-23
宜:重構程式碼
T1
70分做法就是把1e6以內的直接父親都暴力處理出來,詢問時線上遞迴處理即可。
100分做法,發現每一層的最後一個數都是斐波那契數的一個值,並且一個數的父親是這個數減去它的上一層的斐波那契數。求兩個數祖先時一直遞迴往上跳,直到跳到二者相同時返回。
Code
#include<algorithm> #include<iostream> #include<cmath> #include<cstring> #include<cstdio> #include<queue> #include<stack> using namespace std; namespace EMT{ typedef long long ll; inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;} #define pf printf #define F(i,a,b) for(register int i=a;i<=b;i++) #define D(i,a,b) for(register int i=a;i>=b;i--) inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");} ll f[65]={0,1,2};int m; ll max(ll a,ll b){return a>b?a:b;} int getdp(ll x){ int l=1,r=60,ans=0; while(l<=r){ int mid=(l+r)>>1; if(f[mid]<x)l=mid+1,ans=mid; else r=mid-1; }return ans; } inline ll getfa(ll x,ll y,int dep){ if(x==y)return x; else if(x>y)return getfa(x-f[dep],y,getdp(max(x-f[dep],y))); else return getfa(x,y-f[dep],getdp(max(x,y-f[dep]))); } inline short main(){ F(i,3,60)f[i]=f[i-1]+f[i-2]; m=read(); F(i,1,m){ ll x=read(),y=read(),z=getdp(max(x,y)); pi(getfa(x,y,z));pn(); } return 0; } } int main(){return EMT::main();}
T2
有一個點卡了我好久啊。。。
不過我是不會放棄騙分分塊的!
加了個小優化,結果一直T的點反而變成最快的點了...
Code
#include<bits/stdc++.h> namespace EMT{ inline int read(){int x=0;char ch=getchar();while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x;} inline void write(int x){ static int sta[35];int top=0; do{sta[++top]=x-(x/10)*10,x/=10;}while(x); while(top) putchar(sta[top--]+'0'); putchar('\n'); } inline void swap(int &a,int &b){int x=a;a=b,b=x;} const int N=3e5+10; short sum[400][N]; int size,n,m,a[N],pos[N],L,R,sp,x,c,ans; inline short main(){ n=read();m=read(); size=pow(n,5.0/8.0); for(int i=1;i<=n;i++)a[i]=read(),pos[i]=(i-1)/size+1,++sum[pos[i]][a[i]]; while(m--){ sp=read(); if(sp==1){ L=read(),R=read(),c=read(),ans=0; if(pos[L]==pos[R]){ if(R-L+1<=size/2)for(int i=L;i<=R;i++)ans+=(a[i]==c); else{ ans=sum[pos[L]][c]; for(int i=size*(pos[L]-1)+1;i<=L-1;i++)ans-=(a[i]==c); for(int i=R+1;i<=size*pos[L];i++)ans-=(a[i]==c); } write(ans); }else{ if(pos[L]*size-L+1<=size/2)for(int i=L;i<=pos[L]*size;i++)ans+=(a[i]==c); else{ ans=sum[pos[L]][c]; for(int i=size*(pos[L]-1)+1;i<=L-1;i++)ans-=(a[i]==c); } for(int i=pos[L]+1;i<=pos[R]-1;i++)ans+=sum[i][c]; if(R-(pos[R]-1)*size<=size)for(int i=size*(pos[R]-1)+1;i<=R;i++)ans+=(a[i]==c); else{ ans+=sum[pos[R]][c]; for(int i=R+1;i<=size*pos[R];i++)ans-=(a[i]==c); } write(ans); } }else{ x=read(); if(pos[x]==pos[x+1])swap(a[x],a[x+1]); else{ --sum[pos[x]][a[x]];++sum[pos[x]][a[x+1]]; --sum[pos[x+1]][a[x+1]];++sum[pos[x+1]][a[x]]; swap(a[x],a[x+1]); } } } return 0; } } int main(){return EMT::main();}
T3
不知道為什麼一直92...重構程式碼後才過掉了。
倒序列舉是考場上想到了,不過1-512沒想到,只想到了\(O(n^2)\)
40分:
列舉檢視是否有衝突的即可。
100分:
使用並查集,特判一個數的二倍是不是完全平方數。
Code
#include<algorithm> #include<iostream> #include<cmath> #include<cstring> #include<cstdio> #include<queue> #include<stack> using namespace std; int n,k; inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;} #define pf printf #define F(i,a,b) for(register int i=a;i<=b;i++) #define D(i,a,b) for(register int i=a;i>=b;i--) inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");} namespace EMT{ bool v[300000];int a[300000],ans[300000],cnt; inline bool is(int x){int y=sqrt(x);return y*y==x;} inline bool check(int x,int l,int r){ if(r-l+1>=512){F(i,1,512)if(v[i*i-x])return 0;} else F(i,l,r)if(is(a[i]+x))return 0; return 1; } inline void clean(int l,int r){ F(i,l,r)v[a[i]]=0; } inline short main(){ D(i,n,1)a[i]=read(); int key=1;v[a[1]]=1; F(i,2,n)if(!check(a[i],key,i-1))clean(key,i-1),key=i,v[a[i]]=1,ans[++cnt]=n-i+1;else v[a[i]]=1; pi(cnt+1);pn();D(i,cnt,1)pi(ans[i]); return 0; } } namespace emt{ inline int max(int a,int b){return a>b?a:b;} inline int min(int a,int b){return a<b?a:b;} const int N=1.5e5; int a[500000],ans[500000],fa[500000],maxn,vis[500000],co,cnt; inline int find(int x){return (x==fa[x])?x:fa[x]=find(fa[x]);} inline bool is(int x){int y=sqrt(x);return y*y==x;} inline void clean(int l,int r){F(o,l,r)vis[a[o]]=0,fa[a[o]]=a[o],fa[a[o]+N]=a[o]+N;} inline short main(){ int key=n;bool fl; F(i,1,n)a[i]=read(),maxn=max(maxn,a[i]); F(i,1,maxn)fa[i]=i,fa[i+N]=i+N; D(i,n,1){ fl=0; if(vis[a[i]]){ if(is(a[i]*2)){ F(j,1,512){ if(vis[a[i]]==2||fa[a[i]+N]!=a[i]+N){ fl=1;break; } if(j*j<a[i])continue; if(j*j>a[i]+maxn)break; if(vis[j*j-a[i]]&&j*j!=a[i]*2){ fl=1;break; } } if(fl){ ans[++cnt]=i; F(j,i,key){ fa[a[j]]=a[j];fa[a[j]+N]=a[j]+N; vis[a[j]]=0; } key=i; } } }else{ F(j,1,512){ if(j*j<a[i])continue; if(j*j>a[i]+maxn)break; if(vis[j*j-a[i]]){ if(vis[j*j-a[i]]==2&&is((j*j-a[i])*2)){ fl=1; break; } int x1=find(a[i]),x2=find(a[i]+N),y1=find(j*j-a[i]),y2=find(j*j-a[i]+N); if(x1==y1){ fl=1; break; } fa[y2]=x1; fa[x2]=y1; } } if(fl){ ans[++cnt]=i; F(j,i,key){ fa[a[j]]=a[j];fa[a[j]+N]=a[j]+N; vis[a[j]]=0; } key=i; } } vis[a[i]]++; } pi(cnt+1);pn(); D(i,cnt,1)pi(ans[i]); return 0; } } int main(){ n=read();k=read(); if(k==1)return EMT::main();else return emt::main();}