CSP-S 2019————Emiya 家今天的飯————DP+思維

題解:本題主要考查DP+思維。
簡要題意:一個矩陣,要求每行只選一個節點,每列選的節點不能超過所有選的節點的一半,不能不選,給出每個節點的選擇方案數,求總方案數。
1.DP+思維:
(1).維護每列已選的節點複雜度太大,應該不行,所以先不考慮每列不超過一半,求出總數,再減去不合法的方案數,應用逆向思維轉換問題。
(2).設dp[i][j][k]dp[i][j][k]​表示前ii行選jj個節點,當前枚舉到的列選kk個節點的方案數,但是這樣複雜度很高,必須優化。限制條件k>j/2k>⌊j/2⌋,可以得到2k+nj>n2k+n−j>n,就可以剪去無用狀態。
轉移方程:

    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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章