CF489F 做题记录
前置芝士:dp
思路
设 \(f_{i,j,k}\) 表示枚举到第 \(i\) 行时,有 \(j\) 列 \(1\) 的个数为 \(0\),\(k\) 列 \(1\) 的个数为 \(1\)。
因为最终我们要求每行每列都有两个 \(1\),我们控制每行来调控每列,答案为 \(f_{n,0,0}\)。
因为每一行会有两个 \(1\) 被加上,于是我们分类讨论:
- 当加到两个出现次数为 \(0\) 的列上,我们多出了两个出现次数为 \(1\) 的,少了两个出现次数为 \(0\) 的。此时一共有 \(C_{j+2}^{2}\) 种选择方案。所以有:\(f_{i,j,k}\gets f_{i-1,j+2,k-2} \times C_{j+2}^{2}\)。
- 当加到一个出现次数为 \(1\) 的列,另一个为 \(0\) 的列上,出现次数为 \(1\) 的加减刚好抵消,少了一个出现次数为 \(0\) 的。此时一共有 \((j+1)\times k\) 种选择方案。所以有:\(f_{i,j,k}\gets f_{i-1,j+1,k} \times (j+1)\times k\)。
- 当加到两个出现次数为 \(1\) 的列上,我们多出了两个出现次数为 \(0\) 的,少了两个出现次数为 \(1\) 的。此时一共有 \(C_{k+2}^{2}\) 种选择方案。所以有:\(f_{i,j,k}\gets f_{i-1,j,k+2} \times C_{k+2}^{2}\)。
稍微卡常,记得减少取模次数,删掉冗余转移(当 \(k\) 为奇数时答案为 \(0\))。
时间复杂度:\(O(n^3)\)。
难点/坑点:无。
点击查看代码
#include<bits/stdc++.h>
#define int ll
#define pii pair<int,int>
#define pll pair<long long,long long>
#define ll long long
#define i128 __int128
#define mem(a,b) memset((a),(b),sizeof(a))
#define m0(a) memset((a),0,sizeof(a))
#define m1(a) memset(a,-1,sizeof(a))
#define lb(x) ((x)&-(x))
#define lc(x) ((x)<<1)
#define rc(x) (((x)<<1)|1)
#define pb(G,x) (G).push_back((x))
#define For(a,b,c) for(int a=(b);a<=(c);a++)
#define Rep(a,b,c) for(int a=(b);a>=(c);a--)
#define in1(a) a=read()
#define in2(a,b) a=read(), b=read()
#define in3(a,b,c) a=read(), b=read(), c=read()
#define in4(a,b,c,d) a=read(), b=read(), c=read(), d=read()
#define fst first
#define scd second
#define dbg puts("IAKIOI")
using namespace std;
int read() {
int x=0,f=1; char c=getchar();
for(;c<'0'||c>'9';c=getchar()) f=(c=='-'?-1:1);
for(;c<='9'&&c>='0';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
return x*f;
}
void write(int x) { if(x>=10) write(x/10); putchar('0'+x%10); }
int mod = 998244353;
int qpo(int a,int b) {int res=1; for(;b;b>>=1,a=(a*a)%mod) if(b&1) res=res*a%mod; return res; }
int inv(int a) {return qpo(a,mod-2); }
#define maxn 510
int n,m;
int cnt[maxn],c1,c0;
int f[2][maxn][maxn];
void work() {
cin>>n>>m>>mod;
const int MOD=mod;
For(i,1,m) {
string s;
cin>>s;
For(j,1,n) cnt[j]+=s[j-1]-'0';
}
For(i,1,n) if(cnt[i]==1) c1++; else if(cnt[i]==0) c0++;
f[m&1][c0][c1]=1;
For(i,m+1,n) For(j,0,n) For(k,0,n) if((k&1)==0&&j+k<=n) {
f[i&1][j][k]=0;
if(k>=2) f[i&1][j][k]+=f[(i-1)&1][j+2][k-2]*((j+2)*(j+1)/2);
f[i&1][j][k]+=f[(i-1)&1][j+1][k]*(j+1)*k;
(f[i&1][j][k]+=f[(i-1)&1][j][k+2]*((k+2)*(k+1)/2))%=MOD;
}
cout<<f[n&1][0][0]<<'\n';
}
signed main() {
// freopen("data.in","r",stdin);
// freopen("myans.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
double stt=clock();
int _=1;
// _=read();
// cin>>_;
For(i,1,_) {
work();
}
cerr<<"\nTotal Time is:"<<(clock()-stt)*1.0/1000<<" second(s)."<<'\n';
return 0;
}
本文来自博客园,作者:coding_goat_qwq,转载请注明原文链接:https://www.cnblogs.com/CodingGoat/p/18841438

浙公网安备 33010602011771号