https://atcoder.jp/contests/abc317
F - Nim
题意
给定整数 n,a1,a2,a3。求解符合以下条件的 (x1,x2,x3) 的个数:
- 1≤xi≤n
- xi 是 ai 的倍数
- x1⊕x2⊕x3=0
结果对 998244353 取模。
数据范围:1≤n≤1018,1≤ai≤10。
题解
数位dp,但是状态设计又和常规的有些不同。感觉还是见得太少了,也不够灵活。
设 fi,j1,j2,j3,r1,r2,r3 表示处理到二进制下从低到高的第 i 位,第 1,2,3 个数的低 i 位是否不超过 n 的低 i 位,第 1,2,3 个数对 a1,a2,a3 取模结果为 r1,r2,r3 的方案数。转移时只需要考虑一下三个数该位置填什么(保证异或和为 0)。最终 f60,1,1,1,0,0,0 就是答案。不过结果还需要去除掉某些数为 0 的情况。只需要减去 1+⌊lcm(a2,a3)n⌋+⌊lcm(a1,a3)n⌋+⌊lcm(a1,a2)n⌋ 就可以了。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| #include <bits/stdc++.h> using namespace std; typedef long long ll; const int p=998244353; int a[3]; ll n,f[65][2][2][2][15][15][15]; ll lcm(ll x,ll y) {return x*y/__gcd(x,y)%p;} int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin>>n>>a[0]>>a[1]>>a[2]; for(int i=0;i<=1;i++) for(int j=0;j<=1;j++) for(int k=0;k<=1;k++) if((i^j^k)==0) f[0][i<=(n&1)][j<=(n&1)][k<=(n&1)][i%a[0]][j%a[1]][k%a[2]]++; for(int t=0;t<60;t++) for(ll i=0;i<=1;i++) for(ll j=0;j<=1;j++) for(ll k=0;k<=1;k++) for(int t1=0;t1<=1;t1++) for(int t2=0;t2<=1;t2++) for(int t3=0;t3<=1;t3++) for(int t4=0;t4<a[0];t4++) for(int t5=0;t5<a[1];t5++) for(int t6=0;t6<a[2];t6++) if((i^j^k)==0) { int bit=n>>(t+1)&1; f[t+1][(i<=bit&&t1)||i<bit][(j<=bit&&t2)||j<bit][(k<=bit&&t3)||k<bit][((i<<(t+1))+t4)%a[0]][((j<<(t+1))+t5)%a[1]][((k<<(t+1))+t6)%a[2]]+=f[t][t1][t2][t3][t4][t5][t6]%=p; } ll ans=f[60][1][1][1][0][0][0]; ans=(ans-1+p)%p; ans=(ans-n/lcm(a[1],a[2])%p+p)%p; ans=(ans-n/lcm(a[0],a[2])%p+p)%p; ans=(ans-n/lcm(a[0],a[1])%p+p)%p; cout<<ans<<'\n'; return 0; }
|
G - Rearranging
题意
给出一个 n×m 的矩阵,里面 1∼n 每个数恰好出现了 m 次。现在可以重排每一行,要求最终的矩阵每列都是 1∼n 的排列。输出最终的答案矩阵,若不行,则输出 −1。
数据范围:1≤n,m≤100。
题解
每行可以重排,但是一行一共有哪些数是确定的。所以可以想到这样建图:建立一张二分图,i 向 ai,j 连边(i 为左部点,ai,j 为右部点)。跑一次二分图最大匹配,这样就确定了第一列的答案。将这些匹配边删去,然后再继续跑最大匹配。一共跑 m 次,就做完了。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
| #include <bits/stdc++.h> using namespace std; const int N=105; int a[N][N],ans[N][N]; const int inf=0x3f3f3f3f; struct edge { int to,nxt; int c; }e[2*N*N]; int cnt=1,head[2*N]; int s,t; int d[2*N],cur[2*N]; void add(int u,int v,int c) { e[++cnt]={v,head[u],c};head[u]=cnt; e[++cnt]={u,head[v],0};head[v]=cnt; } bool bfs() { memset(d,0,sizeof(d)); queue<int> q; d[s]=1;q.push(s); while(!q.empty()) { int u=q.front();q.pop(); for(int i=head[u];i;i=e[i].nxt) { int v=e[i].to; if(d[v]==0&&e[i].c) { d[v]=d[u]+1;q.push(v); if(v==t) return true; } } } return false; } int dfs(int u,int mf) { if(u==t) return mf; int sum=0; for(int i=cur[u];i;i=e[i].nxt) { cur[u]=i; int v=e[i].to; if(d[v]==d[u]+1&&e[i].c) { int res=dfs(v,min(mf,e[i].c)); e[i].c-=res; e[i^1].c+=res; sum+=res; mf-=res; if(mf==0) break; } } if(sum==0) d[u]=0; return sum; } int dinic() { int flow=0; while(bfs()) { memcpy(cur,head,sizeof(cur)); flow+=dfs(s,inf); } return flow; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n,m;cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { cin>>a[i][j]; add(i,n+a[i][j],1); } s=0,t=2*n+1; for(int i=1;i<=n;i++) add(s,i,1),add(i+n,t,1); for(int i=1;i<=m;i++) { if(dinic()<n) { cout<<"NO"<<'\n'; return 0; } for(int j=3;j<=2*n*m+1;j+=2) { if(e[j].c==1) { ans[e[j].to][i]=e[j^1].to-n; e[j].c=e[j^1].c=0; } } for(int j=2*n*m+3;j<=cnt;j+=2) if(e[j].c==1) { e[j^1].c=1; e[j].c=0; } } cout<<"Yes"<<'\n'; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cout<<ans[i][j]<<" \n"[j==m]; return 0; }
|