1.题目链接。题目大意,给出n个数据,从中删除1-3个,在剩下的数据中选取10个数问这些数据能不能组成87.
2.emmm。最开始看到这个题瞬间想到的就是母函数,但是分析了一下,如果那样做需要枚举所有的组合,显然是不可能的,立刻否定了这个想法。然后想背包,想到了三维dp[i][j][k]:前i个数据里面选j个和是k。这样似乎有门,最后看了一下询问,发现询问是远比答案的数量大的,所以先预处理好,询问的时候直接查表。那样需要做2w次左右的01背包,理论上来说是OK的,然后又加了一个bitset优化一下。提交,没错,WA了。。。。。然后没有发现错误。。。就把核心部分删了重写一遍,就A了。。。这个代码可以优化的地方还是有很多的,比如那个i,j,k.这三个数是具有轮换对称性的,所以我们可以在每次输入的时候排序,这样在标记的时候就会少2倍常数。
#include<bits/stdc++.h>
#include<bitset>
using namespace std;
#pragma warning(disable:4996)
const int N = 60;
int n, a[N];
int vis[N][N][N];
bitset<100>dp[11];
int check(int x, int y, int z)
{
for (int i = 1; i <= n; i++)
dp[i].reset();
dp[0][0] = 1;
for (int i = 1; i <= n; i++)
{
if (i != x && i != y && i != z)
{
for (int j = 9; j >= 0; j--)
dp[j + 1] |= (dp[j] << a[i]);
}
}
if (dp[10][87]==1)
return 1;
return 0;
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
memset(vis, 0, sizeof(vis));
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++)
{
if (check(i, j, k))
{
vis[i][j][k] = vis[i][k][j] = 1;
vis[j][i][k] = vis[j][k][i] = 1;
vis[k][i][j] = vis[k][j][i] = 1;
}
}
int Q, i, j, k;
scanf("%d", &Q);
while (Q--)
{
scanf("%d%d%d", &i, &j, &k);
if (vis[i][j][k])
puts("Yes");
else
puts("No");
}
}
}