Matrix
题解
本来打着很快的,但是卡常硬是把这道题给卡了一个下午,于是就叫它“贞卡常”了
先令表示将一个大小的矩阵,每个格子都涂成黑白,没有任何行与列全为黑的方案数。
根据容斥,枚举其中全为黑的方格数,可以得到。
于是答案便为
将的表达式带进去,可以得到
设,有
记,,这两者可以分别用和处理出来,
带入原式得。时间复杂度。
然后你就惊奇的发现你T了。
卡常卡半天还是过不了。
其实与的式子可以进一步简化得,同理
我们将那个提出来,得到,最后再将乘进去,就极大的减小了常数。
得到
但你发现你还是得卡半天的常才过得去。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
using namespace std;
#define MAXN 3005
typedef long long LL;
typedef pair<int,int> pii;
const double eps=1e-9;
const int mo=998244353;
const int N=3000;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,m,a,b,pow2[MAXN*MAXN];
int fa[MAXN],fb[MAXN],ans,C[MAXN][MAXN];
int add(const int x,const int y){return x+y>=mo?x+y-mo:x+y;}
void init(){
pow2[0]=1;for(int i=1;i<N*N;i++)pow2[i]=add(pow2[i-1],pow2[i-1]);
for(int i=0;i<=N;i++)C[i][0]=C[i][i]=1;
for(int i=1;i<=N;i++)
for(int j=1;j<i;j++)
C[i][j]=add(C[i-1][j-1],C[i-1][j]);
}
signed main(){
//freopen("test.in","r",stdin);
init();
while(~scanf("%d %d %d %d",&n,&m,&a,&b)){
fa[a]=fb[b]=1;ans=0;
for(int i=a+1;i<=n;i++)
for(int j=a;j<i;j++)
fa[i]=(fa[i]-1ll*C[i-1][j-1]*fa[j])%mo;
for(int i=b+1;i<=m;i++)
for(int j=b;j<i;j++)
fb[i]=(fb[i]-1ll*C[i-1][j-1]*fb[j])%mo;
for(int i=a;i<=n;i++)fa[i]=1ll*fa[i]*C[n][i]%mo;
for(int i=b;i<=m;i++)fb[i]=1ll*fb[i]*C[m][i]%mo;
for(int i=a;i<=n;i++)
for(int j=b;j<=m;j++)
ans=(ans+1ll*pow2[(n-i)*(m-j)]*fa[i]%mo*fb[j])%mo;
if(ans<0)ans+=mo;printf("%d\n",ans);
for(int i=a;i<=n;i++)fa[i]=0;
for(int i=b;i<=m;i++)fb[i]=0;
}
return 0;
}