热身训练4 Eighty seven

Eighty seven

简要题意:

n个卡片,其中第i个卡片的数值为$a[i]$。一共q次询问,每次询问将删去其中3个卡片(可能删除若干相同的卡片)后,问能否选出10个卡片,数值之和等于87。

n50,q100000

分析:

当我们知道删去哪些卡片后,这是一道很显然的背包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;
}

 

posted @ 2021-08-18 21:45  kzsn  阅读(121)  评论(0)    收藏  举报