hdu 2082 找单词(母函数)

来源:互联网 发布:桌面上软件打不开 编辑:程序博客网 时间:2024/06/01 12:42

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2082

解题方案:母函数

  1. 假设只有A、B、C三个字母,且每个字母只能用一次,可以构造出母函数G(x)=(1+x)(1+x2)(1+x3),指数代表价值,其中1=x0,代表不取,价值贡献为0。
    (1+x):即(x0+x1),代表字母A不选或者选。
    (1+x2):即(x0+x2),代表字母B不选或者选。
    (1+x3):即(x0+x3),代表字母C不选或者选。
    G(x)=(1+x)(1+x2)(1+x3)=1+x+x2+2x3+x4+x5+x6,就可以得到所有能够组成的价值(指数),以及组成这些价值的方案数(系数)。
  2. 假设只有A、B、C三个字母,且每个字母可以用无限多次,则由上面的推导,可知此时母函数为G(x)=(1+x+x2+...)(1+x2+x4+...)(1+x3+x6+...)
  3. 本题就是更加一般的情况:

    定理:设从n元集合S={a1,a2,a3,...,an}中取元素进行组合,若限定元素ai出现的次数集合为Mi(1in),则该组合数序列的母函数为G(x)=ni=1(mMixm)

    本题只需要在上述定理中将x的幂m再乘上一个权重Vi,其中Vi=i,1i26,接下来就可以模拟计算多项式乘法了,从而得到结果。

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <string>#include <cmath>#include <vector>#include <queue>#include <stack>#include <set>#include <map>using namespace std;#define FOR(i,k,n) for(int i=k;i<n;i++)#define FORR(i,k,n) for(int i=k;i<=n;i++)#define scan(a) scanf("%d",&a)#define scann(a,b) scanf("%d%d",&a,&b)#define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c)#define mst(a,n)  memset(a,n,sizeof(a))#define ll long long#define N 55#define mod 1000000007#define INF 0x3f3f3f3fconst double eps=1e-8;const double pi=acos(-1.0);int a[N];//存储多项式相乘的结果,a[i]代表指数为i的项的系数int tmp[N];int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int t;    scan(t);    while(t--)    {        mst(a,0);        a[0]=1;//在多项式乘法链的首部添加辅助多项式(1+0*x^1+0*x^2+...+0*x^50)        FORR(i,1,26)//乘上第i个多项式        {            int cnt;            scan(cnt);            mst(tmp,0);            FORR(j,0,50)//模拟多项式乘法,前i-1项的51个元素和第i项cnt+1个元素相乘            {                FORR(k,0,cnt)                {                    if(j+k*i>50) break;                    tmp[j+k*i]+=a[j];//此处数组a存着前i-1个多项式相乘的结果                }            }            FORR(j,0,50) a[j]=tmp[j];//更新数组a        }        int ans=0;        FORR(i,1,50) ans+=a[i];        printf("%d\n",ans);    }    return 0;}
0 0
原创粉丝点击