ARC 107簡要題解
阿新 • • 發佈:2021-07-07
Atcoder Regular Contest 107
A&B
隨便做吧。
C
行列分開討論。容易發現能交換這個條件具有傳遞性,那麼找出連通塊,每個連通塊的貢獻是塊大小的階乘,乘起來即可。
#include<bits/stdc++.h> using namespace std; inline int read() { int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return x*f; } const int N=60; int a[N][N],c[N]; struct bcj { int f[N]; void init(int n){for(int i=1;i<=n;i++)f[i]=i;} int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);} void merge(int x,int y){f[getf(y)]=getf(x);} }t1,t2; int p[N],c1[N],c2[N]; int main() { int n=read(),k=read(); p[0]=1; for(int i=1;i<=n;i++)p[i]=(long long)p[i-1]*i%998244353; for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)a[i][j]=read(); t1.init(n),t2.init(n); for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { bool f=1; for(int l=1;l<=n;l++)f&=(a[i][l]+a[j][l]<=k); if(f)t1.merge(i,j); } } for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { bool f=1; for(int l=1;l<=n;l++)f&=(a[l][i]+a[l][j]<=k); if(f)t2.merge(i,j); } } for(int i=1;i<=n;i++)c1[t1.getf(i)]++,c2[t2.getf(i)]++; int ans=1; for(int i=1;i<=n;i++)ans=(long long)ans*p[c1[i]]%998244353,ans=(long long)ans*p[c2[i]]%998244353; printf("%d",ans); return 0; }
*D
可以等價地看作這樣一個操作:一個數初始為 \(0\),做 \(n\) 次操作,每次可以 \(x\gets x+1\) 然後任意除以一個 \(2^p\)(需要滿足 \(2^p\mid x\)),問有多少種情況使得最後 \(x=n\)。這樣就可以直接 dp 了。
#include<bits/stdc++.h> using namespace std; inline int read() { int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return x*f; } const int N=3010; int f[N][N*2]; int main() { f[0][0]=1; int n=read(),k=read(); for(int i=1;i<=n;i++)for(int j=i;j>=1;j--)f[i][j]=f[i-1][j-1]+f[i][j*2],f[i][j]%=998244353; printf("%d",f[n][k]); return 0; }
E
打表找規律可以發現:當 \(\min\{i,j\}>4\) 時,\(a_{i,j}=a_{i-1,j-1}\),處理前四行、前四列即可。
//#pragma GCC optimize(3) //#pragma GCC target("avx") //#pragma GCC optimize("Ofast") //#pragma GCC optimize(2) #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<map> using namespace std; inline int read() { int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return x*f; } const int N=3010; int mex(int x,int y) { for(int i=0;i<=2;i++) if(i!=x&&i!=y)return i; return 0; } map<pair<int,int>,int> a; #define mp make_pair int b[N][N]; int main() { int n=read(); if(n<=3000) { int ans[3]={0,0,0}; for(int i=1;i<=n;i++)b[1][i]=read(); for(int i=2;i<=n;i++)b[i][1]=read(); for(int i=2;i<=n;i++)for(int j=2;j<=n;j++)b[i][j]=mex(b[i-1][j],b[i][j-1]); for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)ans[b[i][j]]++; printf("%d %d %d",ans[0],ans[1],ans[2]); } else { for(int i=1;i<=n;i++)a[mp(1,i)]=read(); for(int i=2;i<=n;i++)a[mp(i,1)]=read(); for(int i=2;i<=n;i++)a[mp(2,i)]=mex(a[mp(1,i)],a[mp(2,i-1)]); for(int i=3;i<=n;i++)a[mp(i,2)]=mex(a[mp(i-1,2)],a[mp(i,1)]); for(int i=3;i<=n;i++)a[mp(3,i)]=mex(a[mp(2,i)],a[mp(3,i-1)]); for(int i=4;i<=n;i++)a[mp(i,3)]=mex(a[mp(i-1,3)],a[mp(i,2)]); for(int i=4;i<=n;i++)a[mp(4,i)]=mex(a[mp(3,i)],a[mp(4,i-1)]); for(int i=5;i<=n;i++)a[mp(i,4)]=mex(a[mp(i-1,4)],a[mp(i,3)]); long long ans[3]={0,0,0}; for(int i=4;i<=n;i++)ans[a[mp(4,i)]]+=min(n-4,n-i); for(int i=5;i<=n;i++)ans[a[mp(i,4)]]+=min(n-i,n-4); for(map<pair<int,int>,int>::iterator it=a.begin();it!=a.end();it++)ans[it->second]++; printf("%lld %lld %lld",ans[0],ans[1],ans[2]); } }
F
還沒做。