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;
}
posted @ 2025-04-22 19:29  coding_goat_qwq  阅读(13)  评论(0)    收藏  举报