題解:本題主要考查DP+思維。
簡要題意:一個矩陣,要求每行只選一個節點,每列選的節點不能超過所有選的節點的一半,不能不選,給出每個節點的選擇方案數,求總方案數。
1.DP+思維:
(1).維護每列已選的節點複雜度太大,應該不行,所以先不考慮每列不超過一半,求出總數,再減去不合法的方案數,應用逆向思維轉換問題。
(2).設表示前行選個節點,當前枚舉到的列選個節點的方案數,但是這樣複雜度很高,必須優化。限制條件,可以得到,就可以剪去無用狀態。
轉移方程:
dp[j][k]=(dp[j][k]+dp[j-1][k]*(sum[j]-a[j][i]))%mod;
dp[j][k+1]=(dp[j][k+1]+dp[j-1][k])%mod;
dp[j][k+2]=(dp[j][k+2]+dp[j-1][k]*a[j][i])%mod;
代碼如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
long long dp[201][3001],a[201][3001],sum[2001];
long long ans=1,n,m;
int mod=998244353;
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
sum[i]=(sum[i]+a[i][j])%mod;
}
ans=(ans*(sum[i]+1))%mod;
}
ans=(ans+mod-1)%mod;
for(int i=1;i<=m;i++)
{
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int j=1;j<=n;j++)
for(int k=0;k<=2*(j-1);k++)
{
dp[j][k]=(dp[j][k]+dp[j-1][k]*(sum[j]-a[j][i]))%mod;
dp[j][k+1]=(dp[j][k+1]+dp[j-1][k])%mod;
dp[j][k+2]=(dp[j][k+2]+dp[j-1][k]*a[j][i])%mod;
}
for(int j=n+1;j<=2*n;j++)
ans=(ans+mod-dp[n][j])%mod;
}
printf("%lld",ans);
return 0;
}