题目传送门
解题思路:
对于每一个列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 }