输出到文件 meal.out 中。
仅一行一个整数,表示所求方案数对 998, 244, 353 取模的结果。
Sample Input1
2 3
1 0 1
0 1 1
Sample Input2
3 3
1 2 3
4 5 0
6 0 0
Sample Input3
5 5
1 0 0 1 1
0 1 0 1 0
1 1 1 1 0
1 0 1 0 1
0 1 1 0 1
Sample Output1
3
Sample Output2
190
Sample Output3
742
发现当一种菜不合法(即种数大于k/2)时,其它所有的菜都是合法的,因此我们可以用所有的方案减去不合法方案得到答案。
总数就是每一行(总和+1)乘起来-1,表示每一行可以选这么多数也可以不选,但是最后不能一个数都不选。
可以发现不合法方案就是每一列选的个数超过选的总数的一半,因为这一列已经不合法了(超过总数的议案),所以其他列一定是合法的。根据这个性质我们就只用做一次容斥了,那么我们可以设f[i][j][k]表示这一列(设为第l列)的前i行中选了一共选了j行,第l列一共选了k个的方案。
首先f[i][j][k]=f[i-1][j][k](i>1)
如果选a[i][l]这个数,f[i][j][k]+=f[i-1][j-1][k-1]*a[i][l]
若果不选a[i][l]这个数,f[i][j][k]+=f[i-1][j-1][j]*(sum[i]-a[i][l])(这一行其他数的总和)。
最后ans就减去f[n][j][k](k>j/2)就可以了。
时间复杂度是O(mn^3)。
我们考虑如何优化dp,我们发现n是优化不掉的,并且我们只需要k>j/2就可以了,那么其实可以将j和k压为一维dp,将式子化一下,得到:k-j/2>0
2k-j>0
j-2k<0
(j-k)-k<0
观察发现,j-k是除了这一列中其他选的数的个数,而k是这一列的个数,因此,我们相当于用一个新的j'=j-2k表示前i个数中不选这一列的数的个数与选这一列的个数的差为j'时的方案数。
那么f[i][j]就可以从三种递推。
f[i][j]=f[i][j-1]
如果选a[i][l],f[i][j]+=f[i-1][j+1]*a[i][l]。
如果不选a[i][l],f[i][j]+=f[i-1][j-1]*(sum[i]-a[i][l])。
最后我们要减去的答案就是那些f[n][i](i<0)。
这样就能优化到O(mn^2)了。
#include
#include
#include
#define I int
#define ll long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define N 110
#define M 998244353
using namespace std;
I n,m,x;
ll a[N][2010],f[N][N][N],ans=1,s[N];
void rd(I &x){
x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
}
void inc(ll &x,ll y){
x+=y;x-=(x/M)*M;
}
I main(){
freopen("meal.in","r",stdin);
freopen("meal.out","w",stdout);
rd(n),rd(m);
F(i,1,n){
F(j,1,m){
rd(x);a[i][j]=x;
s[i]+=a[i][j];
}
ans=(ans*s[i]+ans)%M;
}
--ans;
F(l,1,m){
mem(f,0);
F(i,0,n) f[i][0][0]=f[0][i][0]=1;
f[1][1][0]=s[1]-a[1][l];
F(i,2,n){
f[i][1][0]=f[i-1][1][0]+s[i]-a[i][l];
F(j,2,i){
f[i][j][0]=(f[i-1][j][0]+f[i-1][j-1][0]*(s[i]-a[i][l])%M)%M;
}
}
F(k,1,n){
F(i,k,n){
F(j,k,i){
if(i>1) f[i][j][k]=f[i-1][j][k];
inc(f[i][j][k],f[i-1][j-1][k-1]*a[i][l]);
inc(f[i][j][k],f[i-1][j-1][k]*(s[i]-a[i][l]));
}
}
}
F(j,1,n){
F(k,1,j) if(k>j/2) inc(ans,-f[n][j][k]);
}
}
printf("%lld\n",ans);
return 0;
}
#include
#include
#include
#define I int
#define ll long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define N 110
#define M 998244353
using namespace std;
I n,m,x;
ll a[N][2010],f[N][N*3],ans=1,s[N];
void rd(I &x){
x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
}
void inc(ll &x,ll y){
x+=y;x-=(x/M)*M;
}
I main(){
freopen("meal.in","r",stdin);
freopen("meal.out","w",stdout);
rd(n),rd(m);
F(i,1,n){
F(j,1,m){
rd(x);a[i][j]=x;
// s[i]+=a[i][j];
inc(s[i],a[i][j]);
}
ans=(ans*s[i]+ans)%M;
}
--ans;
F(l,1,m){
mem(f,0);
F(i,1,n) f[i][N]=1;
f[1][N+1]=s[1]-a[1][l],f[1][N-1]=a[1][l];
F(i,2,n){
F(j,-i,i){
f[i][N+j]=f[i-1][N+j];
inc(f[i][N+j],f[i-1][N+j+1]*a[i][l]);
inc(f[i][N+j],f[i-1][N+j-1]*(s[i]-a[i][l]));
}
}
F(i,N-n,N-1) inc(ans,-f[n][i]+M);
}
printf("%lld\n",ans);
return 0;
}
作者:zsjzliziyang
QQ:1634151125
转载及修改请注明
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/103321717