首页 > 其他分享 >Codeforces 1781H1 - Window Signals (easy version)

Codeforces 1781H1 - Window Signals (easy version)

时间:2023-05-12 22:36:49浏览次数:41  
标签:图案 pw int Codeforces 合法 Signals Window MAXN &&

很套路的一道题,把 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

相关文章

  • Codeforces Round 872 (Div. 2)
    CodeforcesRound872(Div.2)感谢灵茶山艾府A(脑筋急转弯)给一个回文字符串,找出最长的不回文子串。子串可以是不连续的。没有则输出-1;如果全都是一个字母,那就是-1否则是n-1。因为在原来回文的基础上总可以去掉一个使得不回文(前提是不是全部都是一个字母)B(贪心)给出n*m个数,......
  • Windows——Windows11右键经典栏与传统栏转换
    图1.Windows11右键默认为经典菜单栏图2.传统右键菜单栏/显示更多选项由经典右键菜单栏变为传统右键菜单栏【图1变图2】运行reg.exeadd"HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32"/f/ve将【显示更多选项】作为默......
  • Windows查看端口情况
    一、查看Windows目前所有使用端口netstat-ano二、查看指定的端口netstat-ano|findstr3389三、使用tasklist命令查看指定PID对应的进程名tasklist|findstr283664  ......
  • windows task
    Win+Randtypingtaskschd.mscschtasks.exe/Create Addanewscheduledtask/tn Nameoftask/sc schedulefrequency(MINUTE,HOURLY,DAILYandsoon)/d Onwhichdayordayofmonththetaskshallbescheduled.Youcanuse*forschedulingoneveryday......
  • 修改Windows远程桌面的端口
    一、图形界面下修改启动注册表编辑器。(在“搜索”框中键入regedit。)导航到以下注册表子项:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TerminalServer\WinStations\RDP-Tcp查找端口号单击“编辑”>“修改”,然后单击“十进制”。键入新端口号,然后单击“确定”......
  • 更改微信PC版(电脑版、windows版)的消息提示音
    目标:声音文件包含在微信PC版安装路径中的「WeChatResource.dll」文件中,修改它。路径举例:C:\ProgramFiles(x86)\Tencent\WeChat\[3.9.2.26] 用到的软件:eXeScope下载地址:https://www.123pan.com/s/kW3DVv-aHxJA.html复制链接(破解版)https://ro.softpedia-sec......
  • sysperp之windows10 Sysperp 之 win10
    关于win10中 sysperp应用程序本博主刚刚踩的坑如果你是工作电脑切有且只有一个盘则千万千万千万(重要事情说三遍)不要运行 这个东西否则你有可能会陷入无限循环之无法启动原系统。或者说你已经备份好,但是要做好无限重启的准备。我现在已经换了另外一台电脑在写这个文章。......
  • Idea快捷键大全(Windows)
    Ctrl快捷键介绍Ctrl+F在当前文件进行文本查找(必备)Ctrl+R在当前文件进行文本替换(必备)Ctrl+Z撤销(必备)Ctrl+Y删除光标所在行或删除选中的行(必备)Ctrl+X剪切光标所在行或剪切选择内容Ctrl+C复制光标所在行或复制选择内容Ctrl+D复制光标所在行......
  • windows 2008 r2扩展磁盘
    1.首先,给主机添加磁盘(物理或者虚拟)2.其次,找到磁盘管理,如果是脱机状态,右键磁盘名(这里是磁盘2),点击联机 3.在打开的【初始化磁盘】窗口勾选磁盘后,务必选择【GPT(GUID分区表)】,不能使用MBR。  4.选择GPT后,接着点击【确定】按钮。  5.右键点击想扩展的磁盘,选择扩展卷,......
  • window docker nginx容器 创建容器,把本地目录可以映射到nginx容器中
    在Windows环境下,您可以按照以下步骤创建一个映射了本地目录的Nginx容器:1.首先,创建一个本地目录,例如`C:\nginx`。2.使用以下命令启动Nginx容器,并将本地目录映射到容器中:```shdockerrun--namemy-nginx-p8080:80-vC:/nginx:/usr/share/nginx/html:ro-dnginx......