很套路的一道题,把 F1 写了,F2 感觉和 F1 gap 不太大就懒得写了/shui
首先需要明白大致思路:直接计算 \(2^{nm-k}-1\) 之所以会算重,是因为对于同一种图案,可能把它放在很多位置都是合法的。那么显然我们需要选一个代表元来把它的贡献唯一化,非常自然的想法就是把它固定在最左上角那个合法位置(即,取 \(x\) 最小那个,如果有多个取 \(y\) 最小的)。\(k\) 只有 \(2\),因此考虑从这个角度对 \(k\) 进行分类讨论。
首先 \(k=0\) 是 trivial 的,而因为没有坏掉的灯,所以必然可以把左上角固定在 \((1,1)\),所以这等价于第一行和第一列必须有亮着的点。容斥直接 \(O(1)\) 算即可。
\(k=1\) 的情况还是仿照 \(k=0\) 的情况。值得注意的一个点是,如果我们假设最左上角的合法点在 \((x,y)\),那么如果我们不知道这个图案的尺寸 \(h\times w\),我们就没法判断一个在 \((x,y)\) 前面的点 \((x',y')\) 不合法究竟是因为 \(x'>n-h+1\) 还是 \(y'>m-w+1\) 还是因为坏掉的那个点在矩形中而对应的图案中的点刚好是亮着的,因此考虑先枚举图案的尺寸,这样对于前面的所有点,给我们图案的限制是坏的那个位置在图案中对应的点必须是必亮点,而又因为图案尺寸限制的存在,必须强制钦定上下左右边界必须至少有一个亮着的点。这部分可以容斥,大概有 \(2^4\) 的常数,这样总复杂度 \(n^4·16\),但是注意到 \(h\) 的枚举是不必须的,因为如果 \((x,y)\) 满足下边界不超过 \(n\times m\) 矩阵的尺寸,那 \((x',y')\) 也超不过,这样复杂度少一个 \(n\),且常数降为 \(8\)。
\(k=2\) 也类似,还是枚举 \(w\) 和第一个合法的点,对于前面的每个不合法点,如果两个坏掉的位置都在矩形内,给图案的限制是这两个位置至少有一个亮的点,如果只有一个在矩形内,限制则是这个位置必须是亮的。对于前者我们就在两点间连一条边,显然连出的是若干条链,直接在链上 DP 即可。
const int MAXN=40;
const int MOD=998244353;
int n,m,k,pw[MAXN*MAXN+5];
namespace ZERO{void solve(){printf("%d\n",(pw[n*m-1]+1ll*pw[(n-1)*(m-1)]*(pw[n-1]-1)%MOD*(pw[m-1]-1))%MOD);}}
namespace ONE{
bool ban[MAXN+5][MAXN+5],mst[MAXN+5][MAXN+5];int x1,y1;
void solve(){
scanf("%d%d",&x1,&y1);int res=0;
for(int w=1;w<=m;w++){
memset(mst,0,sizeof(mst));
for(int i=1;i<=n;i++)for(int j=1;j<=m-w+1;j++){
for(int k=0;k<8;k++){
memset(ban,0,sizeof(ban));
if(x1>=i&&j<=y1&&y1<=j+w-1)ban[x1-i+1][y1-j+1]=1;
for(int x=n-i+2;x<=n;x++)for(int y=1;y<=w;y++)ban[x][y]=1;
if(k&1){for(int y=1;y<=w;y++)ban[1][y]=1;}
if(k>>1&1){for(int x=1;x<=n-i+1;x++)ban[x][1]=1;}
if(k>>2&1){for(int x=1;x<=n-i+1;x++)ban[x][w]=1;}
int c=0,flg=0;
for(int x=1;x<=n;x++)for(int y=1;y<=w;y++)
c+=(!ban[x][y]&&!mst[x][y]),flg|=(ban[x][y]&&mst[x][y]);
if(!flg){
if(__builtin_parity(k))res=(res-pw[c]+MOD)%MOD;
else res=(res+pw[c])%MOD;
}
}
if(!(x1>=i&&j<=y1&&y1<=j+w-1))goto END;
else mst[x1-i+1][y1-j+1]=1;
}END:;
}
printf("%d\n",res);
}
}
namespace TWO{
bool ban[MAXN+5][MAXN+5],mst[MAXN+5][MAXN+5];int x1,y1,x2,y2;
int hd[MAXN*MAXN+5],nxt[MAXN*MAXN*2+5],to[MAXN*MAXN*2+5],ec;
void adde(int u,int v){
to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;
to[++ec]=u;nxt[ec]=hd[v];hd[v]=ec;
}
bool vis[MAXN*MAXN+5];
int getid(int x,int y,int w){return (x-1)*w+y;}
int len,a[MAXN*MAXN+5],dp[MAXN*MAXN+5][2];pii rid[MAXN*MAXN+5];
void dfs(int id){
vis[id]=1;pii pp=rid[id];
if(ban[pp.fi][pp.se])a[++len]=0;
else if(mst[pp.fi][pp.se])a[++len]=1;
else a[++len]=-1;
for(int e=hd[id];e;e=nxt[e])if(!vis[to[e]])dfs(to[e]);
}
void solve(){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);int res=0;
for(int w=1;w<=m;w++){
memset(mst,0,sizeof(mst));memset(hd,0,sizeof(hd));ec=0;
for(int i=1;i<=n;i++)for(int j=1;j<=m-w+1;j++){
bool flg1=(x1>=i&&j<=y1&&y1<=j+w-1);
bool flg2=(x2>=i&&j<=y2&&y2<=j+w-1);
for(int k=0;k<8;k++){
memset(ban,0,sizeof(ban));
if(flg1)ban[x1-i+1][y1-j+1]=1;
if(flg2)ban[x2-i+1][y2-j+1]=1;
for(int x=n-i+2;x<=n;x++)for(int y=1;y<=w;y++)ban[x][y]=1;
if(k&1){for(int y=1;y<=w;y++)ban[1][y]=1;}
if(k>>1&1){for(int x=1;x<=n-i+1;x++)ban[x][1]=1;}
if(k>>2&1){for(int x=1;x<=n-i+1;x++)ban[x][w]=1;}
int flg=0;
for(int x=1;x<=n;x++)for(int y=1;y<=w;y++)
flg|=(ban[x][y]&&mst[x][y]);
if(!flg){
memset(vis,0,sizeof(vis));
for(int x=1;x<=n;x++)for(int y=1;y<=w;y++)
rid[getid(x,y,w)]=mp(x,y);
int prd=1;
for(int x=1;x<=n;x++)for(int y=1;y<=w;y++){
if(!vis[getid(x,y,w)]){
len=0;dfs(getid(x,y,w));
for(int t=0;t<=len;t++)dp[t][0]=dp[t][1]=0;
for(int t=0;t<2;t++)if(a[1]!=(t^1))dp[1][t]=1;
for(int t=2;t<=len;t++)for(int q=0;q<2;q++)if(a[t]!=(q^1))
for(int r=0;r<2;r++)if(q||r)dp[t][q]=(dp[t][q]+dp[t-1][r])%MOD;
int sum=0;
for(int t=0;t<2;t++)sum=(sum+dp[len][t])%MOD;
prd=1ll*prd*sum%MOD;
}
}
if(__builtin_parity(k))res=(res-prd+MOD)%MOD;
else res=(res+prd)%MOD;
}
}
if(flg1&&flg2)adde(getid(x1-i+1,y1-j+1,w),getid(x2-i+1,y2-j+1,w));
else if(flg1)mst[x1-i+1][y1-j+1]=1;
else if(flg2)mst[x2-i+1][y2-j+1]=1;
else goto END;
}END:;
}
printf("%d\n",res);
}
}
void solve(){
scanf("%d%d%d",&n,&m,&k);
if(!k)ZERO::solve();
else if(k==1)ONE::solve();
else TWO::solve();
}
int main(){
for(int i=(pw[0]=1);i<=MAXN*MAXN;i++)pw[i]=pw[i-1]*2%MOD;
int qu;scanf("%d",&qu);while(qu--)solve();return 0;
}
/*
4
2 2 1
1 1
2 2 1
1 2
2 2 1
2 1
2 2 1
2 2
*/
标签:图案,pw,int,Codeforces,合法,Signals,Window,MAXN,&&
From: https://www.cnblogs.com/tzcwk/p/Codeforces-1781H1.html