【HDU5890】Eighty seven

题目大意:给定 N 个数,M 个询问,每次询问如果去掉三个数(可能相同),能否选择恰好 10 个数字,凑出 87 这个数。

题解:骚操作。。
集合凑数问题是一个很经典的模型,即:背包问题。
先进行预处理,每次枚举三个位置,跑一遍背包,计算出删除这三个位置的数是否可以组合出 87 这个数字。查询的时候直接 \(O(1)\) 回答即可。
但是发现预处理复杂度为 \(O(5*50*50*50*50*10*100)\),过不了这题。由于背包中每一位都是以布尔值,因此进行 bitset 优化,即:优化掉 100 这一维,复杂度处以 32,刚刚好卡过。。

代码如下

#include <bits/stdc++.h>
using namespace std;


int n,m,num[51];
bitset<100> dp[11];
bool valid[51][51][51];

void make(int x,int y,int z){
	for(int i=0;i<=10;i++)dp[i].reset();
	dp[0][0]=1;
	for(int i=1;i<=n;i++){
		if(i==x||i==y||i==z||num[i]>87)continue;
		for(int j=10;j;j--){
			dp[j]|=dp[j-1]<<num[i];
		}
	}
	if(dp[10][87])valid[x][y][z]=1;
	else valid[x][y][z]=0;
}
int main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++)scanf("%d",&num[i]);
		for(int i=1;i<=n;i++)
			for(int j=i;j<=n;j++)
				for(int k=j;k<=n;k++)
					make(i,j,k);
		scanf("%d",&m);
		while(m--){
			int x[3];
			for(int i=0;i<3;i++)scanf("%d",&x[i]);
			sort(x,x+3);
			puts(valid[x[0]][x[1]][x[2]]?"Yes":"No");
		}
	}	
	
	return 0;
}
posted @ 2019-06-24 16:48  shellpicker  阅读(207)  评论(0编辑  收藏  举报