hdu5890(背包,bitset)

题意:给你n(n<=50)个数,m( m<=1e5 )次询问,每次询问给你三个数,问在给出的数里面存不存在任意取10个(不包含这三个数)的数的和刚好为87,每次询问输出Yes/No。

 1)bitset?

  C++中可以直接用的一个类。

  bitset<num> name;

  可以看作一个大小为num的数组,里面的元素只能是0或1,有趣的是它能进行和数组一样的操作又能把它当做一个整体(当做一个二进制数)来进行位运算操作。

  1个应用:当做一个数的集合,可以用一个name<<a对集合中的所有元素+a操作(若集合为空,则操作无效),用|符实现两个集合的取交集。

  例如:name1 : 0000010010001001(包含0,3,7,10四个元素)

     name1<<2 :0001001000100100(包含2,5,9,12四个元素)

     name1|name1<<2 :0001011010101101(包含0,3,7,10,2,5,9,12 八个元素,相当于只用了两个位操作就得到了对该集合所有元素加上2/不加上2 的所有结果)

 2)本题分析

  dp分析即可,Bitset[10](使用10个数)由Bitset[9]获得。初始化所有元素为空,但要设置一个含0元素的集合,具体见代码。

  分析下时间复杂度:50*50*50*50*10=6.25e7 (超时的边缘)

  //如果用01背包来做这题,dp[10][87][0/1],时间复杂度:6.25e7*87=5.4375e9

上代码,交了好几次,基本都卡过去了,但最好也只是902ms(在G++上交)

 

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<math.h>
#include<queue>
#include<string.h>
#include<algorithm>
#include<bitset> 
#define PI acos(-1.0)
using namespace std; 
int n,a[60];
bool reco[60][60][60][2]; //记录该3个数是否计算过,是否yes 

bool check(int x,int y,int z)
{
	if(reco[x][y][z][0]==1) return reco[x][y][z][1];
	
	bitset<90> bs[12];
	
	bs[0][0]=1;
	for(int i=1;i<=n;i++)
	{	if(*(a+i)>87) continue;
		if(i==x||i==y||i==z) continue;
	
		for(int j=10;j>=1;j--)
			*(bs+j)|=*(bs+j-1)<<*(a+i);
			
		if(bs[10][87]==1) break;
	}
	reco[x][y][z][1]=(bs[10][87]==1);
	reco[x][y][z][0]=1;
	return reco[x][y][z][1];
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{	
		memset(reco,0,sizeof(reco));
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
			scanf("%d",&a[i]);
			
		int q;
		scanf("%d",&q);
		while(q--)
		{
			int x[5];
			scanf("%d%d%d",x,x+1,x+2);
			sort(x,x+3);
			if(reco[x[0]][x[1]][x[2]][1]) printf("Yes\n");
			else if(check(x[0],x[1],x[2])) printf("Yes\n");
			else printf("No\n");
		}
	}
}

 

以及AtCoder Grand Contest #020 by tourist  C题 (单纯bitset)

链接:https://agc020.contest.atcoder.jp/tasks/agc020_c 

AC代码:

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<math.h>
#include<queue>
#include<string.h>
#include<bitset> 
#define PI acos(-1.0)
using namespace std; 

int main()
{
	bitset<4000005> bs(1);
	int n,x,sum=0;
	scanf("%d",&n);
	
	for(int i=0;i<n;i++)
		{
			scanf("%d",&x);
			bs|=bs<<x;
			sum+=x;
		}
	if(n==1)
	{
		printf("%d\n",sum);
		return 0;
	}
	for(int i=(double)sum/2.0+0.5;i<=sum;i++)
		{
			if(bs[i]==1)
			{
				printf("%d\n",i);
				break;
			}
		}
	return 0;
}

  

posted @ 2018-01-20 22:57  hzhuan  阅读(198)  评论(0编辑  收藏  举报