【集训队互测2016】消失的源代码
SOL:
毒瘤题。做一个两个点还觉得这道题很有意思,但10个点写下来就是心累了。
point 1:
对小数据观察发现每个字母唯一确定另一个字母。把26个字母之间的映射关系打表就好了。
#include<bits/stdc++.h> using namespace std; char ch[107]="yfrbkgimujvphatdsnelozcxwq"; int T; char p[1000007]; signed main() { freopen("input1.txt","r",stdin); freopen("output1.txt","w",stdout); scanf("%d",&T); scanf("%d",&T); while (T--) { scanf("%s",p+1); int len=strlen(p+1); for (int i=1;i<=len;i++) putchar(ch[p[i]-'a']); putchar(10); } }
point 2:
一拿到手,就发现这个函数的增长是O(N^2)的。写了个高消发现系数是2016 4 10 ,但是跑不过样例,所以把1到20全部打出来看了一遍,发现应该是膜了一个数。
#include<bits/stdc++.h> #define N 205 using namespace std; const double eps=1e-8; int n; double a[N][N],del; bool gauss(){ for(int i=1;i<=n;i++){ int k=i; for(int j=i+1;j<=n;j++)if(fabs(a[j][i])>fabs(a[k][i]))k=j; if(fabs(del=a[k][i])<eps)return 0; for(int j=i;j<=n+1;j++)swap(a[i][j],a[k][j]); for(int j=i;j<=n+1;j++)a[i][j]/=del; for(k=1;k<=n;k++)if(k!=i){ del=a[k][i]; for(int j=i;j<=n+1;j++)a[k][j]-=a[i][j]*del; } } return 1; } int T; long long p; __int128 x; #define mo (243990-10657) void write(__int128 x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);} inline void writeln(__int128 x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('\n'); } inline void writel(__int128 x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); } int main(){ freopen("input2.txt","r",stdin); freopen("output2.txt","w",stdout); scanf("%d",&T); scanf("%d",&T); while (T--) { scanf("%lld",&p); x=p; // printf("%lld\n",); writeln((x*x*2016+4*x+10)%mo); } // cerr<<sqrt(100/pi); }
point 3:
方法同point 2吧,应该看到出应该是O(N^0.5)这个级别的。算了下系数,发现是根号 π。
#include<bits/stdc++.h> #define N 205 using namespace std; const double eps=1e-8; int n; double a[N][N],del; bool gauss(){ for(int i=1;i<=n;i++){ int k=i; for(int j=i+1;j<=n;j++)if(fabs(a[j][i])>fabs(a[k][i]))k=j; if(fabs(del=a[k][i])<eps)return 0; for(int j=i;j<=n+1;j++)swap(a[i][j],a[k][j]); for(int j=i;j<=n+1;j++)a[i][j]/=del; for(k=1;k<=n;k++)if(k!=i){ del=a[k][i]; for(int j=i;j<=n+1;j++)a[k][j]-=a[i][j]*del; } } return 1; } int T; long long p; __int128 x; #define mo (243990-10657) void write(__int128 x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);} inline void writeln(__int128 x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('\n'); } inline void writel(__int128 x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); } #define pi acos(-1) int main(){ freopen("input3.txt","r",stdin); freopen("output3.txt","w",stdout); scanf("%d",&T); scanf("%d",&T); while (T--) { scanf("%lld",&p); printf("%lld\n",(int)sqrt(p/pi)); // writeln((x*x*2016+4*x+10)%mo); } // cerr<<sqrt(100/pi); }
point 4:
怎么说呢,长得像一张图,然后发现完全图的时候 answer=n*n,链的时候也是这样的,但边集为空的时候为n,所以应该能猜出来是sigma 联通图大小的平方。
#include<bits/stdc++.h> #define N 200007 using namespace std; long long ans,f[N],siz[N]; int T,n,m,x,y,a,b; int gf(int x){ return x==f[x]?x:f[x]=gf(f[x]); } signed main () { // T=1; freopen("input4.txt","r",stdin); freopen("output4.txt","w",stdout);
#include<bits/stdc++.h> #define N 200007 #define SIZ 24 #define eho(x) for(int i=head[x];i;i=net[i]) #define v fall[i] using namespace std; long long ans,dep[N],anw; int T,n,m,x,y,z,f[N][SIZ],a,b,dd[N],fall[N<<1],net[N<<1],tot,head[N],cost[N]; inline void add(int x,int y,int co) { fall[++tot]=y; net[tot]=head[x]; head[x]=tot; cost[tot]=co; } void dfs(int x,int fa) { // cerr<<x<<endl; dd[x]=dd[fa]+1; f[x][0]=fa; for (int i=1;i<SIZ;i++) f[x][i]=f[f[x][i-1]][i-1]; eho(x) if (v!=fa) dep[v]=dep[x]+cost[i],dfs(v,x); } int pku(int x,int y){ if (dd[x]<dd[y]) swap(x,y); for (int i=SIZ-1;~i;i--) if (dd[f[x][i]]>=dd[y]) x=f[x][i]; if (x==y) return x; for (int i=SIZ-1;~i;i--) if (f[x][i]^f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } signed main () { // T=1; // freopen("test.txt","r",stdin); freopen("input5.txt","r",stdin); freopen("output5.txt","w",stdout); scanf("%d",&T); scanf("%d",&T); while (T--) { // memset(f,0,sizeof f); memset(head,0,sizeof head); tot=0; scanf("%d%d",&n,&m);anw=0; for (int i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } dfs(1,0); while (m--) { scanf("%d%d",&x,&y); ans=dep[x]+dep[y]-2*dep[pku(x,y)]; anw^=ans; } printf("%lld\n",anw); } return 0; }
scanf("%d",&T); scanf("%d",&T); while (T--) { scanf("%d%d",&n,&m);ans=0; for (int i=1;i<=n;i++) f[i]=i,siz[i]=0; while (m--) { scanf("%d%d",&x,&y); a=gf(x); b=gf(y); f[a]=b; } for(int i=1;i<=n;i++) siz[gf(i)]++; for(int i=1;i<=n;i++) ans+=1ll*siz[i]*siz[i]; printf("%lld\n",ans); } }
point 5:先是发现正是一颗树,又发现偶数组询问等于没有询问,所以猜答案是互相xor的。而单组询问是路径两点路径长。
#include<bits/stdc++.h> #define N 200007 #define SIZ 24 #define eho(x) for(int i=head[x];i;i=net[i]) #define v fall[i] using namespace std; long long ans,dep[N],anw; int T,n,m,x,y,z,f[N][SIZ],a,b,dd[N],fall[N<<1],net[N<<1],tot,head[N],cost[N]; inline void add(int x,int y,int co) { fall[++tot]=y; net[tot]=head[x]; head[x]=tot; cost[tot]=co; } void dfs(int x,int fa) { // cerr<<x<<endl; dd[x]=dd[fa]+1; f[x][0]=fa; for (int i=1;i<SIZ;i++) f[x][i]=f[f[x][i-1]][i-1]; eho(x) if (v!=fa) dep[v]=dep[x]+cost[i],dfs(v,x); } int pku(int x,int y){ if (dd[x]<dd[y]) swap(x,y); for (int i=SIZ-1;~i;i--) if (dd[f[x][i]]>=dd[y]) x=f[x][i]; if (x==y) return x; for (int i=SIZ-1;~i;i--) if (f[x][i]^f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } signed main () { // T=1; // freopen("test.txt","r",stdin); freopen("input5.txt","r",stdin); freopen("output5.txt","w",stdout); scanf("%d",&T); scanf("%d",&T); while (T--) { // memset(f,0,sizeof f); memset(head,0,sizeof head); tot=0; scanf("%d%d",&n,&m);anw=0; for (int i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } dfs(1,0); while (m--) { scanf("%d%d",&x,&y); ans=dep[x]+dep[y]-2*dep[pku(x,y)]; anw^=ans; } printf("%lld\n",anw); } return 0; }
point 6:发现输入和point 5一样,不费什么力气就发现了除了单组询问是路径上最短边边权以外和point 5没区别。还有一个坑点就是x==y时的return的不是0,是1987654321
#include<bits/stdc++.h> #define N 200007 #define SIZ 24 #define int long long #define eho(x) for(int i=head[x];i;i=net[i]) #define v fall[i] using namespace std; long long ans,dep[N],anw; int T,n,m,x,y,z,cst[N][SIZ],f[N][SIZ],a,b,dd[N],fall[N<<1],net[N<<1],tot,head[N],cost[N]; inline void add(int x,int y,int co) { fall[++tot]=y; net[tot]=head[x]; head[x]=tot; cost[tot]=co; } void dfs(int x,int fa) { // cerr<<x<<endl; dd[x]=dd[fa]+1; f[x][0]=fa; for (int i=1;i<SIZ;i++) f[x][i]=f[f[x][i-1]][i-1],cst[x][i]=min(cst[x][i-1],cst[f[x][i-1]][i-1]); eho(x) if (v!=fa) cst[v][0]=cost[i],dfs(v,x); } int pku(int x,int y){ if (x==y) return 1987654321; int anw=LONG_LONG_MAX; if (dd[x]<dd[y]) swap(x,y); for (int i=SIZ-1;~i;i--) if (dd[f[x][i]]>=dd[y]) anw=min(anw,cst[x][i]),x=f[x][i]; if (x==y) return anw; for (int i=SIZ-1;~i;i--) if (f[x][i]^f[y][i]) anw=min(anw,cst[x][i]),anw=min(anw,cst[y][i]),x=f[x][i],y=f[y][i]; return min(anw,min(cst[x][0],cst[y][0])); } signed main () { T=1; // freopen("test.txt","r",stdin); freopen("input6.txt","r",stdin); freopen("output6.txt","w",stdout); scanf("%lld",&T); scanf("%lld",&T); while (T--) { // memset(f,0,sizeof f); memset(head,0,sizeof head); tot=0; scanf("%lld",&n); cin>>m; anw=0; for (int i=1;i<n;i++) { scanf("%lld%lld%lld",&x,&y,&z); // cin >>x>>y>>z; add(x,y,z); add(y,x,z); // cerr<<z<<endl; } dfs(1,0); int xx; while (m--) { scanf("%lld%lld",&x,&y); // cerr<<x<<' '<<y<<' '<<(xx=pku(x,y))<<endl; anw^=pku(x,y); } printf("%lld\n",anw); } return 0; } //1987654321 //1987654321
point 7:
通过增量法观察发现是gcd的二维前缀和,一个优雅的反演就可以过了。
令f(x,y)为要求的答案,有
f(x,y)* d= D* (x/D)* (y/D)*d
那么就是卷上一个欧拉函数的事情了。
#include<bits/stdc++.h> using namespace std; #define N 1000007 int pim[N],tot,t,n,m; long long mu[N],ans; void pre(){ mu[1]=1; for (int i=2;i<N;i++) { if (!mu[i]) mu[i]=i-1,pim[++tot]=i; for (int j=1;j<=tot&&pim[j]*i<N;j++) { if (i%pim[j]==0) { mu[i*pim[j]]=mu[i]*pim[j]; break; } mu[i*pim[j]]=mu[i]*(pim[j]-1); } } // for (int i=1;i<100;i++) cout<<mu[i]<<' '; for (int i=1;i<N;i++) mu[i]=mu[i-1]+mu[i]; } signed main () { pre(); freopen("input7.txt","r",stdin); freopen("output7.txt","w",stdout); scanf("%d%d",&t,&t); while (t--) { scanf("%d%d",&n,&m); if (n>m) swap(n,m);ans=0; for (int i=1,last;i<=n;i=last+1) { last=min(n/(n/i),m/(m/i)); ans+=1ll*(n/i)*(m/i)*(mu[last]-mu[i-1]); } printf("%lld\n",ans); } return 0; }
point 8:观察发现所有的在序列里的值很小,而且答案和序列里具体是哪个值没有关系,只与序列中的其他数是否相等有关,猜一波发现是字符串相关,再想想就知道是求本质不同的字符串。SAM跑一遍就好了。
#include<bits/stdc++.h> #define SIZ 3000007 using namespace std; int t,n,x; long long ans; struct Node{ int len,ch[26],fa; void clear() { fa=len=0; memset(ch,0,sizeof ch); } }T[SIZ]; int q,p,last=1,tot=1,np,c[SIZ],id[SIZ]; long long dp[SIZ],anw; inline void ext(int x){ q=++tot; T[q].clear(); T[q].len=T[last].len+1; for (;last&&!T[last].ch[x];last=T[last].fa) T[last].ch[x]=q; if (!last) T[q].fa=1; else { p=T[last].ch[x]; if (T[last].len+1==T[p].len) T[q].fa=p; else { np=++tot; T[np]=T[p]; T[np].len=T[last].len+1; T[p].fa=T[q].fa=np; for (;last&&T[last].ch[x]==p;last=T[last].fa) T[last].ch[x]=np; } } last=q; } signed main () { // freopen("test.txt","r",stdin); freopen("input8.txt","r",stdin); freopen("output8.txt","w",stdout); scanf("%d%d",&t,&t); while (t--) { memset(dp,0,sizeof dp); memset(c,0,sizeof c); memset(id,0,sizeof id); memset(T,0,sizeof T); last=tot=1; T[1].clear(); T[0].clear(); scanf("%d",&n); cerr<<n<<"rrsb"<<endl; for (int i=1;i<=n;i++) { scanf("%d",&x);assert(0<=x&&x<26); ext(x); } for (int i=1;i<=tot;i++) c[T[i].len]++; for (int i=1;i<=n;i++) c[i]+=c[i-1]; for (int i=1;i<=tot;i++) id[c[T[i].len]--]=i; dp[1]=1; ans=0; for (int i=0;i<26;i++) if(T[1].ch[i]) dp[T[1].ch[i]]+=dp[1]; for (int i=2;i<=tot;i++) { x=id[i]; for (int j=0;j<26;j++) if (T[x].ch[j]) dp[T[x].ch[j]]+=dp[x]; ans+=dp[x]; } printf("%lld\n",ans); } return 0; }
point 9:求最近点对。玄学暴力复杂度竟然是对的。
#include<bits/stdc++.h> #define db double #define N 2000007 #define exp 1e-5 using namespace std; struct Node{ int x,y; inline bool operator <(const Node&X)const &{ return x<X.x; } }a[N]; db ans; #define Mid (l+r>>1) inline db que(int x,int y){ return sqrt(1ll*(a[x].x-a[y].x)*((a[x].x-a[y].x))+1ll*(a[x].y-a[y].y)*(a[x].y-a[y].y)); } void sol(int l,int r){ if (r-l<=10) { for (int i=l;i<=r;i++) for (int j=i+1;j<=r;j++) ans=min(ans,que(i,j)); return; } sol(l,Mid); sol(Mid+1,r); for (int i=Mid;(a[Mid].x-a[i].x)<ans+exp&&i>=l;i--) for (int j=Mid+1;a[j].x-a[Mid].x<ans+exp&&j<=r;j++) ans=min(ans,que(i,j)); } int t,n; signed main () { // freopen("test.txt","r",stdin); freopen("input9.txt","r",stdin); freopen("output9.txt","w",stdout); scanf("%d%d",&t,&t); while (t--) { scanf("%d",&n); ans=1e18; cerr<<n<<"rrsb\n"; for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y); sort(a+1,a+n+1); sol(1,n); printf("%.3lf\n",ans);
} return 0; }
point 10:发现怎么输入都是invalid input!
那么就输出这个。
#include<bits/stdc++.h> #define db double #define N 2000007 using namespace std; struct Node{ int x,y; inline bool operator <(const Node&X)const &{ return x<X.x; } }a[N]; db ans; #define Mid (l+r>>1) inline db que(int x,int y){ return sqrt((a[x].x-a[y].x)*((a[x].x-a[y].x))+(a[x].y-a[y].y)*(a[x].y-a[y].y)); } void sol(int l,int r){ if (r-l<=10) { for (int i=l;i<=r;i++) for (int j=i+1;j<=r;j++) ans=min(ans,que(i,j)); return; } sol(l,Mid); sol(Mid+1,r); for (int i=Mid;a[Mid].x-a[i].x<ans&&i>=l;i--) for (int j=Mid+1;a[j].x-a[Mid].x<ans&&j<=r;j++) ans=min(ans,que(i,j)); } int t,n; signed main () { // freopen("test.txt","r",stdin); freopen("input10.txt","r",stdin); freopen("output10.txt","w",stdout); scanf("%d%d",&t,&t); while (t--) { printf("invalid input!\n"); } return 0; }
讲道理这题目真毒瘤,不是很难,但我写了一天。