您的位置:首页 > 其它

Wannafly挑战赛11-C:白兔的棋盘(轮廓线DP)

2018-03-09 22:32 344 查看
链接:https://www.nowcoder.com/acm/contest/73/C

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

白兔有一个n*m的棋盘,某些格子是障碍。有k种大小为x*y的矩形图案(x<=2,且矩形不能旋转),每种数量无限个。
白兔可以在棋盘上任意放置图案,要求图案不能放到障碍上,且任意两个图案不相交。问方案数。
两种方案不同为存在一个格子在一种方案中被覆盖,在另一种方案中未被覆盖或者覆盖这两个格子的图案大小或位置不同。 一个矩形正好铺满x行y列的一块区域,不能旋转

输入描述:

第一行三个整数n,m,k(n,m<=15,k<=2*m)
接下来n行,每行m个整数,每个数为0或者1,1表示空格,0表示障碍
最后k行,每行两个数x,y(x<=2,y<=m),任意两对(x,y)不相同

输出描述:

一个数,表示答案,对1e9+7取模
示例1

输入

2 3 2
1 0 0
1 1 0
1 1
1 2

输出

10

示例2

输入

4 4 2
1 0 0 1
0 0 0 0
1 1 1 1
0 1 1 0
1 1
1 2

输出

580
思路:典型的轮廓线上的DP。d[i][j][k]表示从(i,j)开始前m个格子状态为k的方案数。#include<bits/stdc++.h>
using namespace std;
const double PI=acos(-1);
const int MAX=1e6;
const int MOD=1e9+7;
typedef long long ll;
int d[20][20][1<<16];
int x[40],y[40];
int n,m;
int a[20][20],sum[20][20];
int check(int x,int y,int h)//判断是否有障碍,所放置的矩形是否越界
{
if(y+h-1>=m)return 0;
if(y==0)return sum[x][y+h-1]==h;
return sum[x][y+h-1]-sum[x][y-1]==h;
}
int get(int x){return ((x>>m)<<m)^x;}//去掉m个格子之前的状态,本来是对(1<<m)取模的,但是取模耗时,结果超时了。。。
int main()
{
int tot;
scanf("%d%d%d",&n,&m,&tot);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
scanf("%d",&a[i][j]);
sum[i][j]=a[i][j];
if(j)sum[i][j]+=sum[i][j-1];
}
}
for(int i=0;i<tot;i++)scanf("%d%d",&x[i],&y[i]);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(i==0&&j==0)//对(0,0)这点单独处理
{
for(int h=0;h<tot;h++)//枚举矩形,以(0,0)为端点向右放置x=1的矩形
{
if(x[h]==1&&check(i,j,y[h]))d[i][j+y[h]-1][(1<<y[h])-1]=1;
}
if(a[i][j]==1)d[i][j][0]=1;//不放矩形且(i,j)这点是空地
else d[i][j][1]=1; //不放矩形且(i,j)这点是障碍
continue;
}
for(int k=0;k<(1<<m);k++)//枚举前m个格子的状态
{
int pre;
if(j==0)pre=d[i-1][m-1][k];
else pre=d[i][j-1][k];
if(pre==0)continue;
for(int h=0;h<tot;h++)//枚举矩形,以(i,j)为左下顶点放置矩形
{
if(x[h]==2&&i&&check(i,j,y[h])&&(k>>(m-y[h]))==0)
{
d[i][j+y[h]-1][get((k<<y[h])^((1<<y[h])-1))]+=pre;
d[i][j+y[h]-1][get((k<<y[h])^((1<<y[h])-1))]%=MOD;
}
if(x[h]==1&&check(i,j,y[h]))
{
d[i][j+y[h]-1][get((k<<y[h])^((1<<y[h])-1))]+=pre;
d[i][j+y[h]-1][get((k<<y[h])^((1<<y[h])-1))]%=MOD;
}
}
if(a[i][j]==0) //不放矩形且(i,j)这点是障碍
{
d[i][j][get((k<<1)^1)]+=pre;
d[i][j][get((k<<1)^1)]%=MOD;
}

c2c7
else //不放矩形且(i,j)这点是空地
{
d[i][j][get(k<<1)]+=pre;
d[i][j][get(k<<1)]%=MOD;
}
}
}
}
int ans=0;
for(int i=0;i<(1<<m);i++)ans=(ans+d[n-1][m-1][i])%MOD;
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: