[bzoj1025][SCOI2009]游戏

题意:可以转化为:把n分成任意个数,这些数的lcm有多少种  n<=1000

所以把质数筛出来,然后f[i][j]表示前i个质数用j点体力有多少种答案

枚举i,枚举j,枚举选k个,f[i][j]+=f[i-1][j-s[i]*k] 

这样就转化为了一道01背包

复杂度n^1.5*logn

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
bool b[1005];
ll f[1005][1005],s[1005],n,cnt=0;

int pow(int x,int p)
{
    if(p==0)return 0;
    int sum=1;
    for(int i=x;p;p>>=1,i=i*i)
        if(p&1) sum=sum*i;
    return sum;
}

int main()
{
    for(int i=2;i<=1000;i++)
    {
        if(!b[i]) s[++cnt]=i;
        for(int j=1;j<=cnt&&s[j]*i<=1000;j++)
        {
            b[s[j]*i]=1;if(i%s[j]==0)break;    
        }    
    }
    n=read();f[0][0]=1;int i;
    for(i=1;i<=cnt;i++)
    if(s[i]<=n)
    {
        for(int j=0;j<=n;j++)
        {
            for(int k=0;k<=n;k++)
            {
                int x=pow(s[i],k);
                if(x<=j)
                {
                    f[i][j]+=f[i-1][j-x];    
                //    cout<<i<<" "<<j<<" "<<k<<" "<<f[i][j]<<endl;
                }
                else break;    
            }
        }
    }
    else break;ll ans=0;
    for(int j=1;j<=n;j++)ans+=f[i-1][j];
    cout<<ans+1;
    return 0;
}

 

posted @ 2017-03-02 18:35  FallDream  阅读(162)  评论(0编辑  收藏  举报