列表

详情


NC15207. 白金元首与莫斯科

描述

在一个 n x m 的网格区域中存在一个陆军单位需要补给,区域中的每个格子为空地或障碍物中的一种。航空舰队需要派遣若干运输机前往此区域,每一架运输机可以向两个相邻(有一条公共边)的空地投放物资。为防止不必要的损坏,一个标记为空地的格子至多只能得到一次投放。
由于天气原因,陆军单位所在的确切位置并不能确定。因此元首想知道,对于每个空地格子,当陆军单位在其中(视作障碍物)时,用若干(可以为 0)架运输机向其余空地投放任意数量的物资的不同方案数。两个投放方案不同,当且仅当存在一个格子在一个方案中被投放而另一方案中未被投放,或存在两个被投放的格子,在一个方案中被同一架运输机投放而在另一方案中非然。若仍有疑问,请参考【样例 1 解释】。
你需要编写程序帮助元首计算这些值。

输入描述

输入的第一行包含一个正整数 T —— 数据的组数。接下来包含 T 组数据,格式如下,数据间没有空行。
- 第 1 行:两个空格分隔的正整数 n, m —— 网格区域的行数和列数。
- 接下来 n 行:其中第 i 行包含 m 个空格分隔的整数 Ai1, Ai2, ..., Aim —— 其中 Aij = 0 表示第 i 行第 j 列的格子为空地;Aij = 1 表示该格为障碍物

输出描述

对于每组数据输出 n 行,第 i 行包含 m 个空格分隔的整数 Bi1, Bi2, ..., Bim —— 若第 i 行第 j 列的格子为空地,Bij 为该格变为障碍物后投放的方案数;否则 Bij = 0。

示例1

输入:

2 4
0 0 0 0
0 0 0 1

输出:

14 13 10 22
15 11 17 0

说明:

以第 2行第 1列的空地格为例,其变为障碍物后的网格如下图,其中白色格子代表空地,黑色格子代表障碍物。

15种方案如下图所示,不同颜色代表不同运输机的投放位置。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 46ms, 内存消耗: 18836K, 提交时间: 2022-09-27 18:45:33

#include<cstdio>
#include<cstring>
#define ri register int
#define ll long long
#define mo 1000000007
#define maxn 262145
#define fo(i,x,y) for(ri i(x);i<=y;++i)
#define fd(i,x,y) for(ri i(x);i>=y;--i)
using namespace std;
int n,m,a[19][19],f[18][18][maxn],p[21],cnt[2],las,now,q[2][maxn],val[2][maxn],mat[maxn];
int g[maxn],ans[19][19];
inline void add(ri i,ri j,ri bit,ri num){
	if(!f[i][j][bit])q[now][++cnt[now]]=bit;
	f[i][j][bit]+=num;f[i][j][bit]%=mo;
}
inline void add2(ri bit,ri num){
	if(!mat[bit]){
		mat[bit]=++cnt[now];q[now][cnt[now]]=bit;val[now][cnt[now]]=num;
	}
	else val[now][mat[bit]]=(val[now][mat[bit]]+num)%mo;
}
int main(){
	scanf("%d%d",&n,&m);
	fo(i,1,n)
	 fo(j,1,m)scanf("%d",&a[i][j]);
	fo(i,1,n)
	 fo(j,1,m)a[i][j]^=1;
	p[0]=1;fo(i,1,m+1)p[i]=p[i-1]<<1;
	q[now][++cnt[now]]=0;f[0][m][0]=1;
	fo(i,1,n)
	 fo(j,1,m){
	 	las=now;now^=1;cnt[now]=0;
	 	ri prex,prey;
	 	if(j>1)prex=i,prey=j-1;
	 	else prex=i-1,prey=m;
	 	if(j==1){
	 		memcpy(g,f[prex][prey],sizeof(f[prex][prey]));
		    memset(f[prex][prey],0,sizeof(f[prex][prey]));
		    fo(k,1,cnt[las])f[prex][prey][(q[las][k]<<1)&(p[m+1]-1)]=g[q[las][k]];
	 	    fo(k,1,cnt[las])q[las][k]=(q[las][k]<<1)&(p[m+1]-1);
		}
	 	fo(k,1,cnt[las]){
	 		ri bit=q[las][k],l1=(bit>>j-1)&1,l2=(bit>>j)&1,num=f[prex][prey][bit];
	 		if(l1&&l2)continue;
	 		else{
	 			if(l1)add(i,j,bit-p[j-1],num);
	 			else{
	 				if(l2)add(i,j,bit-p[j],num);
	 				else{
	 					add(i,j,bit,num);if(a[i][j]&&a[i+1][j])add(i,j,bit+p[j-1],num);
	 					if(a[i][j+1]&&a[i][j])add(i,j,bit+p[j],num);
					}
				}
			}
		}
		//if(i==1&&j==m)
		//fo(k,1,cnt[now])printf("%d %d %d %d\n",i,j,q[now][k],f[i][j][q[now][k]]);
	 }
	cnt[now]=0;add2(0,1);
	fd(i,n,1)
	 fd(j,m,1){
	 	//printf("YES\n");
	 	ri px,py;las=now;now^=1;cnt[now]=0;memset(mat,0,sizeof(mat));
	 	if(j==m)fo(k,1,cnt[las])q[las][k]>>=1;
	 	if(j>1)px=i,py=j-1;
	 	else px=i-1,py=m;
	 	//printf("fd%d %d %d %d %d\n",i,j,cnt[las],px,py);
	 	fo(k,1,cnt[las]){
	 		//printf("%d %d %d %d\n",i,j,q[las][k],val[las][k]);
	 		ri bit=q[las][k],l1=(bit>>j-1)&1,l2=(bit>>j)&1,num=val[las][k];
	 		if(!l1&&!l2){
	 			ri res=1ll*f[px][py][bit]*num%mo;
	 			//printf("bit %d n1 %d n2 %d %d\n",bit,f[px][py][bit],num,res);
				ans[i][j]+=res;ans[i][j]%=mo;
			}
			if(l1&&l2)continue;
			else{
				if(l1)add2(bit-p[j-1],num);
				else{
					if(l2)add2(bit-p[j],num);
					else{
						add2(bit,num);if(a[i][j]&&a[i][j-1])add2(bit+p[j-1],num);
						if(a[i][j]&&a[i-1][j])add2(bit+p[j],num);
					}
				}
			}
		}
	 }
	fo(i,1,n)
	 fo(j,1,m)if(!a[i][j])ans[i][j]=0;
	fo(i,1,n){
		fo(j,1,m-1)printf("%d ",ans[i][j]);
		printf("%d\n",ans[i][m]);
	}
	return 0;
} 

C++ 解法, 执行用时: 56ms, 内存消耗: 24056K, 提交时间: 2022-06-30 16:19:45

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf 20021225
#define ll long long
#define mdn 1000000007
using namespace std;
 
int f[18][18][1<<17],g[18][18][1<<17];
int bit[18],n,m,top;
int mp[18][18];
 
void add(int &x,int y){x=(x+y)%mdn;}
 
void work()
{
	//int top=(1<<m)-1;
	f[1][1][top]=1;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
	{
		int x=i,y=j+1;
		if(j==m)	x=i+1,y=1;
		if(x>n)	continue;
		for(int st=0;st<=top;st++)
			if(f[i][j][st])
			{
				int tmp=f[i][j][st];
				if((st&bit[j])==0&&mp[i][j])	continue;
				if((st&bit[j])==0)
				{
					add(f[x][y][st|bit[j]],tmp);
					continue;
				}
				if(mp[i][j])	add(f[x][y][st],tmp);
				else
				{
					add(f[x][y][st],tmp);
					add(f[x][y][st^bit[j]],tmp);
					if(j>1&&(st&bit[j-1])==0)	add(f[x][y][st|bit[j-1]],tmp);
				}
			}
	}
	
	g[n][m][top]=1;
	for(int i=n;i;i--)
	for(int j=m;j;j--)
	{
		int x=i,y=j-1;
		if(j==1)	x=i-1,y=m;
		if(x<1)	continue;
		for(int st=0;st<=top;st++)
			if(g[i][j][st])
			{
				int tmp=g[i][j][st];
				if((st&bit[j])==0&&mp[i][j])	continue;
				//printf("%d %d %d %d\n",i,j,st,g[i][j][st]);
				if((st&bit[j])==0)
				{
					add(g[x][y][st|bit[j]],tmp);
					continue;
				}
				if(mp[i][j])	add(g[x][y][st],tmp);
				else
				{
					add(g[x][y][st],tmp);
					add(g[x][y][st^bit[j]],tmp);
					if(j<m&&(st&bit[j+1])==0)	add(g[x][y][st|bit[j+1]],tmp);
				}
			}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	bit[1]=1;top=(1<<m)-1;
	for(int i=2;i<=m;i++)	bit[i]=bit[i-1]<<1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&mp[i][j]);
	work();
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(mp[i][j])
			{
				printf("0 ");
				continue;
			}
			int ans=0;
			for(int s=0;s<=top;s++)
			{
				if(s&bit[j])
					add(ans,(ll)f[i][j][s]*g[i][j][s]%mdn);
				//printf("%d %d %d %d\n",i,j,f[i][j][s],g[i][j][s]);
			}
			printf("%d ",ans);
		}
		printf("\n");
	}
	
	return 0;
}

上一题