HLG 1396 射镖游戏【母函数】
题意:
给你一个运动员的起始分数,分数为 N,你需要计算出有多少种投掷飞镖的方式能够把分数降到0. 不同的
方式意味着: 两两方式之间至少有一种方式的某个步骤和另一个不同,如果两个方式可以通过改变其中某种
方式相应步骤的顺序来使其和另一个方式相同的话,这两种方式算作一种。
分析:
比较明显的母函数,只不过有个地方需要注意,就是要开两个数组来维护总的情况数,即 先求出不包含X2 的情况的
组合数,然后用滚动数组c1 c2来存放至少含有一个X2的情况数,也就是 C数组里面存的都是符合条件的情况,
c[j+step]+={ c[j] 里面的每种情况都符合要求
{ tmp[j] 里面的每种情况都不符合要求
code:
View Code
#include<stdio.h> #include<string.h> #define mod 2011 int main() { // freopen("D:data.in","r",stdin); int c1[1111]; int c2[1111]; int tmp[1111]; int g,a[100],i,j,k,n,top=0; for(i=1;i<=20;i++) { a[top++]=i; a[top++]=i*3; } a[top++]=25; a[top++]=50; g=top-1; for(i=1;i<=20;i++) a[top++]=i*2; for(i=0;i<=1001;i++) { tmp[i]=1; c2[i]=0; } for(i=1;i<g;i++) { for(j=0;j<=1001;j++) for(k=0;j+k<=1001;k+=a[i]) c2[j+k]+=tmp[j]%mod; for(j=0;j<=1001;j++) { tmp[j]=c2[j]%mod; c2[j]=0; } } memset(c1,0,sizeof(c1)); for(i=g;i<top;i++) { for(j=0;j<=1001;j++) for(k=a[i];j+k<=1001;k+=a[i]) c2[j+k]+=tmp[j]%mod; for(j=0;j<=1001;j++) for(k=0;j+k<=1001;k+=a[i]) c2[j+k]+=c1[j]%mod; for(j=0;j<=1001;j++) { c1[j]=c2[j]%mod; c2[j]=0; } } while(scanf("%d",&n),n) printf("%d\n",c1[n]); return 0; }