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
白兔可以在棋盘上任意放置图案,要求图案不能放到障碍上,且任意两个图案不相交。问方案数。
两种方案不同为存在一个格子在一种方案中被覆盖,在另一种方案中未被覆盖或者覆盖这两个格子的图案大小或位置不同。 一个矩形正好铺满x行y列的一块区域,不能旋转
示例2
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;
}
时间限制: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;
}
相关文章推荐
- Wannafly挑战赛11 A-白兔的分身术
- Wannafly挑战赛11 B-白兔的式子
- Wannafly挑战赛11 -A 白兔的分身术
- Wannafly 挑战赛11 B白兔的式子
- Wannafly挑战赛11 D 白兔的字符串 [Hash]
- Wannafly挑战赛11 D-白兔的字符串
- Wannafly挑战赛11 B、白兔的式子
- Wannafly挑战赛11 白兔的式子
- wannafly挑战赛11----白兔的字符串
- Wannafly挑战赛11 B 白兔的式子【阶乘逆元 + 预处理 + 板子】
- Wannafly挑战赛11-白兔的式子(组合数取模)
- Wannafly挑战赛11 白兔的式子 (组合数取模)
- Wannafly挑战赛11 - 白兔的分身术
- Wannafly挑战赛11_D_白兔的字符串(字符串hash)
- Wannafly挑战赛11 D 白兔的字符串 (字符串hash)
- Wannafly挑战赛11 A B D【规律+逆元+字符串hash】
- Wannafly挑战赛12 C 删除子串 (dp)
- Wannafly挑战赛10-B-小H和密码(dp)
- 棋盘覆盖2(1X2骨牌 和 L型骨牌 混合铺满)(强行轮廓线DP)
- Wannafly挑战赛11_A_B_D