NKOI 3701 分享巧克力

P3701分享巧克力
时间限制 : - MS   空间限制 : 65536 KB 
评测说明 : 时限1000ms
问题描述

  给你一块长为x,宽为y的矩形巧克力。你可以对巧克力进行任意次下列操作:
  每次操作可以沿一条直线把一块巧克力切割成两块巧克力,要求切出的两块巧克力的长和宽都是整数。
  问:是否可以经过若干次上述操作,恰好得到n块面积分别为A1,A2,...,An的巧克力(巧克力要恰好用完,不能够有剩余)。如下图所示,给出你一块3*4的巧克力,我们可以将其切割成面积为1,2,3,6的四块巧克力。
NKOI 3701 分享巧克力_第1张图片
  

输入格式

第一行,一个整数n,表示要求切割出的巧克力的块数。
第二行,两个整数x和y,表示初始巧克力的长和宽
第三行,n个空格间隔的整数,表示n块指定的巧克力的面积A1,A2,...,An

输出格式

一行,若能够切割成功输出"Yes",否则输出"No"

样例输入 1


3 4 
6 3 2 1 

样例输出 1

Yes

样例输入 2


2 3 
1 5

样例输出 2

No

提示

1<=n<=15
1<=x,y<=100
1<=Ai<=x*y


来源  改编自la4794
提交

注意到n的范围很小,可以把和n有关的子集作为动态规划状态的一部分,设f[r][c][s]表示边长为r,c的巧克力是否可以切割成面积集合为s

我们可以知道,f[r][c][s]==1,当且仅当:

1.存在1<=r0

2.存在1<=c0

再稍微加一些优化就能过了

#include
#include
using namespace std;
const int maxn=16,maxm=105;
int f[1<>1)+(x&1);}//算出s的二进制位中1的个数
int dp(int s,int x){
	if(mark[s][x])return f[s][x];
	mark[s][x]=1;
	if(bitcount(s)==1)return f[s][x]=1;
	int s0,s1,y=sum[s]/x;
	for(s0=(s-1)&s;s0;s0=(s0-1)&s){
		s1=s^s0;
		if(sum[s0]%x==0&&dp(s0,min(x,sum[s0]/x))&&dp(s1,min(x,sum[s1]/x)))
		    return f[s][x]=1;
		if(sum[s0]%y==0&&dp(s0,min(y,sum[s0]/y))&&dp(s1,min(y,sum[s1]/y)))
		    return f[s][x]=1;
	}
	return f[s][x]=0;
}
int main(){
	int i,x,y,ans,s,n;
	scanf("%d%d%d",&n,&x,&y);
	for(i=0;i

你可能感兴趣的:(动态规划,位运算)