热身训练4 Eighty seven
Eighty seven
简要题意:
n个卡片,其中第i个卡片的数值为$a[i]$。一共q次询问,每次询问将删去其中3个卡片(可能删除若干相同的卡片)后,问能否选出10个卡片,数值之和等于87。
n≤50,q≤100000
分析:
当我们知道删去哪些卡片后,这是一道很显然的背包dp。
dp[i][j]表示:选择了i个卡片,数值之和为j,这个状态行不行,若dp[i][j]=1,则行。否则,不行。
由于数值都是正数,且要求的数值之和为87,所以这个dp耗时O(87*10*n),但由于询问数很多,最终耗时O(87*10*50*100000) = O(4.35*1e9),肯定过不了。
但是,dp值只有0、1,这使得bitset优化成为了可能,优化完后,耗时O(135937500)。
同时,这道题的询问有很多是相同的,需要记录一下来优化。
十分玄学!!!
#include<bits/stdc++.h> using namespace std; bool ans[55][55][55]; bitset<90>s[20]; int a[60],n; void solve(int x,int y,int z) { for(int i=0;i<=11;i++) s[i].reset(); s[0][0]=1; for(int i=1;i<=n;i++){ if(i==x||i==y||i==z||a[i]>87) continue; for(int j=10;j>=1;j--) s[j]|=s[j-1]<<a[i]; } if(s[10][87]==1) ans[x][y][z]=true; else ans[x][y][z]=false; } int main() { int T,Q; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) for(int k=j;k<=n;k++) solve(i,j,k); scanf("%d",&Q); while(Q--) { int x[3]; scanf("%d%d%d",&x[0],&x[1],&x[2]); sort(x,x+3); if(ans[x[0]][x[1]][x[2]]) puts("Yes"); else puts("No"); } } return 0; }