Description
给出nn个数,每次查询删去三个数(可能重复),问是否可能从剩下的数中取十个数使其和为8787
Input
第一行一整数TT表示用例组数,每组用例首先输入一整数,之后输入nn个整数,之后输入一整数qq表示查询数,每组查询输入三个整数表示删去ai,aj,akai,aj,ak(1≤T≤5,1≤n≤50,1≤q≤105)(1≤T≤5,1≤n≤50,1≤q≤105)
Output
对于每组查询,如果删去ai,aj,akai,aj,ak后可以从剩余数中拿十个使得其和为8787则输出YesYes,否则输出NoNo
Sample Input
1
12
1 2 3 4 5 6 7 8 9 42 21 22
10
1 2 3
3 4 5
2 3 2
10 10 10
10 11 11
10 1 1
1 2 10
1 11 12
1 10 10
11 11 12
Sample Output
No
No
No
Yes
No
Yes
No
No
Yes
Yes
Solution
枚举删去的三个数ai,aj,akai,aj,ak,以dp[r][s][t]dp[r][s][t]表示从前rr个数中取个数和为tt的方案是否存在,如果则第rr个数不选,否则根据第个数是否选有转移dp[r][s][t]|=dp[r−1][s−1][t−ar]|dp[r−1][s][t]dp[r][s][t]|=dp[r−1][s−1][t−ar]|dp[r−1][s][t],时间复杂度O(880n4)O(880n4),用bitsetbitset优化一下第三维即可,预处理出所有情况之后对于查询O(1)O(1)输出即可
Code
#include<cstdio>
#include<algorithm>
#include<bitset>
using namespace std;
bitset<88>dp[11];
int T,n,q,a[55],mark[55][55][55];
int check(int i,int j,int k)
{
for(int i=0;i<=10;i++)dp[i].reset();
dp[0][0]=1;
for(int s=1;s<=n;s++)
if(s!=i&&s!=j&&s!=k)
for(int t=10;t>=1;t--)
dp[t]|=dp[t-1]<<a[s];
if(dp[10][87])return 1;
return 0;
}
int main()
{
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++)
mark[i][j][k]=check(i,j,k);
scanf("%d",&q);
while(q--)
{
int b[3];
scanf("%d%d%d",&b[0],&b[1],&b[2]);
sort(b,b+3);
printf("%s\n",mark[b[0]][b[1]][b[2]]?"Yes":"No");
}
}
return 0;
}

本文介绍了一种使用动态规划解决特定数值组合问题的方法。给定一系列整数,在删除三个数后,判断是否能从剩余的数中选出十个数,使它们的总和等于87。文章详细解释了通过枚举和状态转移方程来解决问题的过程,并提供了实现代码。
&spm=1001.2101.3001.5002&articleId=79825030&d=1&t=3&u=a4f2cb856a044e5596640f96ed2e3723)
234

被折叠的 条评论
为什么被折叠?



