hdu 6092
http://acm.hdu.edu.cn/showproblem.php?pid=6092
题意:有两个数组,分别为A数组和B数组,其中B数组是由A数组的子集的和构成的,B[i]代表A在子集的和为i的有多少个,且A,B都是个多重集,也就是说集合里面一个元素可能有多个
思路:因为B数组里面是A的子集的和,那么B数组第一个存在的元素的位置,这个一定代表A里面i元素有B[i]个,因为没有比i要小的元素了。
然后最开始想的是分解,把所有的元素分解成可以由哪些前面的数字的组合构成,然后觉得这样复杂度太高了,你每一个都要递归去找他的和因子,很明显这样不行
然后看了一下官方题解,是用DP,反向的DP,这个思路确实是没有想到过的(其实还是太菜),感觉很巧妙
就是一个B[i] -= B[i-j],j代表当前的A的和,为什么会这样呢
因为B[I-J]代表什么,说明你用B[i-j]+B[j]可以构成一个B[I],减去B[i-j]就是代表减去了用这个i-j这个数构成的情况。
那么最后剩下来的就是代表着B[I]这个数的个数,代表这个数不是由其他因子合成的个数。
最后,我用java写,发现超时,然后用c++的cin输入还是超时,改scanf就可以了
对这些东西还是不熟啊,java好的输入模板也没有
1 #include <iostream> 2 #include <stdio.h> 3 using namespace std; 4 5 int main() 6 { 7 8 int t, m, n; 9 int locy; 10 long long num[10005]; 11 scanf("%d", &t); 12 while ((t--) > 0) 13 { 14 scanf("%d%d", &n, &m); 15 for (int i = 0; i <= m; i++) 16 scanf("%lld",&num[i]); 17 for (int i = 1; i <= n; i++) 18 { 19 locy = 0; 20 for (int j = 1; j <= m; j++) 21 if (num[j] != 0) 22 { 23 locy = j; 24 break; 25 } 26 for (int j = locy; j <= m; j++) 27 num[j] -= num[j - locy]; 28 if (i != n) 29 printf("%d ", locy); 30 else 31 printf("%d\n", locy); 32 } 33 } 34 return 0; 35 }