洛谷 P5664 Emiya 家今天的饭(84分)

题目传送门

解题思路:

对于每一个列c,f[i][j][k]表示到第i行,第c列选了j个,其它列一共选了k个,然后我们读题意发现只要j>k,那就一定是不合法的,然后统计所有方案,减去所有不合法方案,即为答案.

代码里有注释.

//只做了84分,懒得写100分(思路一样),以后可能update.....

84分代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 long long n,m,a[41][501],sum[41],f[41][41][41],p = 998244353,ans = 1,cd;
 8 
 9 int main() {
10     scanf("%lld%lld",&n,&m);
11     for(int i = 1;i <= n; i++) {
12         for(int j = 1;j <= m; j++){
13             scanf("%lld",&a[i][j]);
14             sum[i] += a[i][j] % p;
15         }
16         sum[i] %= p;
17         ans = (ans * (sum[i] + 1) % p) % p;//总方案 
18     }
19     for(int c = 1;c <= m; c++) {
20         memset(f,0,sizeof(f));
21         f[0][0][0] = 1;
22         for(int i = 1;i <= n; i++)
23             for(int j = 0;j <= i; j++)
24                 for(int k = 0;k <= i - j; k++) {
25                     f[i][j][k] = f[i-1][j][k] % p;//不选当前行 
26                     if(j > 0)
27                         f[i][j][k] += a[i][c] * f[i-1][j-1][k] % p;//选第c列 
28                     if(k > 0)
29                         f[i][j][k] += ((sum[i] - a[i][c]) * f[i-1][j][k-1]) % p;//不选第c列 
30                     f[i][j][k] %= p;
31                 }
32         for(int j = 1;j <= n; j++)
33             for(int k = 0;k <= n - j; k++)
34                 if(j > k) 
35                     cd += f[n][j][k];//不合法方案 
36         cd %= p;
37     }
38     printf("%lld",(ans - cd - 1 + p) % p);//-1是因为多加了f[0][0][0]的方案,+p是为了防止负数对答案造成影响. 
39     return 0;
40 } 
原文地址:https://www.cnblogs.com/lipeiyi520/p/12025975.html