杭电1398,1028,1085//赤裸裸的母函数

G(x)=(1+x+x2+x3+x4+…)(1+x4+x8+x12+…)(1+x9+x18+x27+…)…

典型母函数!

//HDOJ_1398  Square Coins
//G(x)=(1+x+x^2+x^3+x^4+…)(1+x^4+x^8+x^12+…)(1+x^9+x^18+x^27+…)…
#include <iostream>
using namespace std;
const int lmax=300;
int c1[lmax+1],c2[lmax+1];
int main(void)
{	int n,i,j,k;
	while (cin>>n &&n)
	{	for (i=0;i<=n;i++)
		{	c1[i]=1;	c2[i]=0;		}//1
		for (i=2;i<=17;i++)//2
		{	for (j=0;j<=n;j++)//3
				for (k=0;k+j<=n;k+=i*i)//4
				{	c2[j+k]+=c1[j];	}
			for (j=0;j<=n;j++)//5
			{	c1[j]=c2[j];	c2[j]=0;	}
		}
		cout<<c1[n]<<endl;
	}
	return 0;
}

几点说明:第i个括号里面的指数为K的系数为j

1: 对c1初始化,由第一个表达式(1+x+x2+..x^17)初始化,把质量从0到17的所有硬币个数都初始化为1.

2: i从2到n遍历,一次模拟手工打开括号,从第二个到低17个括号

3:j 从0到n遍历,这里j就是里第j个变量的系数。.   

4: k表示的是第j个指数,所以k每次增i*i

5:为打开下一个括号准备

//HDOJ_1398  Square Coins
//变化一点点,灵活多多多
…
int main(void)
{	int n,i,j,k;
    int elem[17]={1,4,9,16,25,36,…,169,196,225,256,289}
	while (cin>>n && n!=0)
	{	for (i=0;i<=n;i++)
		{	c1[i]=1;	c2[i]=0;		}
		for (i=2; i<=17; i++)
		{	for (j=0;j<=n;j++)
				for (k=0;k+j<=n; k+=elem[i-1] ) 
				{	c2[j+k]+=c1[j];	}
			for (j=0;j<=n;j++)
			{	c1[j]=c2[j];	c2[j]=0;	}
		}
		cout<<c1[n]<<endl;
	}
	return 0;
}

变化一下就可以敢好多事情啦!

杭电1028:

//整数拆分。由于拆分结果只考虑有几个1几个2几个3...Note that "4 = 3 + 1" and "4 = 1 + 3" is the same in this problem.问题就和之前的砝码邮票什么的一样了。
//G(x)=(1+x+...)(1+x^2+...)(1+x^3....)...(1+x^n)

#include <iostream>
using namespace std;
const int lmax=120;
int c1[lmax+1],c2[lmax+1];
int main(void)
{
    int n,i,j,k;
    while (cin>>n )
    {
        for (i=0; i<=n; i++)
        {
            c1[i]=1;	   //1
            c2[i]=0;
        }
        for (i=2; i<=n; i++) //每个有n个
        {
            for (j=0; j<=n; j++) //3
                for (k=0; k+j<=n; k+=i) //4
                {
                    c2[j+k]+=c1[j];
                }
            for (j=0; j<=n; j++) //5
            {
                c1[j]=c2[j];
                c2[j]=0;
            }
        }
        cout<<c1[n]<<endl;
    }
    return 0;
}

看完上面也许觉得还是不太明白,有点感觉自己蒙混过关的意思,下面看完下面这个题就是很傻逼的方法:
//HDOJ1085
//G(x)=(1+x+x^2+...+x^a)*(1+x^2+x^4...+x^2b)*(1+x^5+x^10+...+x^5c)
#include <iostream>
using namespace std;
const int lmax=8000;
int c1[lmax+1],c2[lmax+1];
int main(void)
{
    int i,j,k,a,b,c;
    while (cin>>a >> b >> c,a||b||c)//这种写法简练
    {
        for (i=0; i<=lmax; i++)
        {
            c1[i]=1;
            c2[i]=0;
        }
        for(i=0; i<=a*1; i++)     c1[i]=1;//第一个括号的系数
        for(i=0; i<=a; i++)
            for(j=0;j<=b*2; j+=2)
                 c2[i+j]+=c1[j];
        for(i=0;i<=a+(b*2);i++)//刷新一下
       {
           c1[i]=c2[i];
           c2[i]=0;
       }
       for(i=0;i<=a+(b*2);i++)

          for(int j=0;j<=c*5;j+=5)

              c2[i+j]+=c1[i];


       for(i=0;i<=a+(b*2)+(c*5);i++)
       {
           c1[i]=c2[i];
           c2[i]=0;
       }
       for(i=0;i<=a+(b*2)+(c*5);i++)
       {
           if(c1[i]==0)//不能支付
           {
              cout  << i << endl;
               break;
           }
       }
       if(i==a+(b*2)+(c*5)+1)  cout << i << endl;//可以支付前面所有的
    }
    return 0;
}

PS:这个资料很不错!




 
 
 

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值