题目:http://acm.hdu.edu.cn/showproblem.php?pid=1709
题意:有个天平,给定砝码重量(各砝码只有1个),天平左右均可放,求不能称出哪些重量
Hints: 跟基本母函数相比,本题特殊在于有负指数,因为下标不能有负的,所以有两种方法
法①:下标扩大,加上一定值
法②:k循环内加上tc[abs(j-k)] += c[j]; 因为j代表的是已称出的重量,【假设放左边是正的】如果j>k自然代表能称出j-k重的,如果j<k,tc[取绝对值后的]虽然增大了对应的系数,但这题不求方案数,只需要知道系数是不是0即可。也不用担心将原本是0的系数变成不是0,因为既然能组成 j-k(负数),那么砝码左右调换就一定能组成k-j(正数->这里决定了系数不是0)。如已称出9和未称出的2对称,那肯定没问题,下标是[abs(9-2)]说明能称出7。而如果是2和9,那么[abs(2-9)]是7,虽然本该是-7。但此时把9和2对换左右即可称出7,故此法正确。
#define MAX 11000
int c[MAX],tc[MAX],res[MAX];
#include<stdio.h>
#include<string.h>
#include<math.h>
int main(){
int n,max,i,j,k,count;
int v[105];
while(scanf("%d",&n)!=EOF){
max = 0;
memset(v,0,sizeof(v));
for(i = 0; i < n; i++){
scanf("%d",&v[i]);
max += v[i];
}
for(i = 0; i <= max; i++){
c[i] = 0;
tc[i] = 0;
}
for(i = 0; i <= v[0]; i+=v[0]){ //只需要(1+x^v[i]),这里不用管x^(-v[i])
c[i] = 1;
}
for(i = 1; i < n; i++){
for(j = 0; j <= max; j++){
for(k = 0; k + j <= max && k <= v[i]; k+=v[i]){
tc[j+k] += c[j];
tc[abs(j-k)] += c[j]; //这条代表负次方
}
}
for(j = 0; j <= max; j++){
c[j] = tc[j];
tc[j] = 0;
}
}
j = 0;
count = 0;
for(i = 0; i <= max; i++){
if(!c[i]){
count++;
res[j++] = i;
}
}
printf("%d\n",count);
if(count > 0){
printf("%d",res[0]);
for(i = 1; i < j; i++){
printf(" %d",res[i]);
}
printf("\n");
}
}
return 0;
}