bzoj1025: [SCOI2009]游戏[数学分析+背包dp]

首先,不难想到的是,最后的排数应该是各个独立循环节的lcm。

并且对于每一个独立的循环节,若其长度为x,那么这个循环中必定有x个不重复的数字。

然而总的数字个数为n,那么显然各个循环节的长度和为n

也就是:

        len1+len2+len3...+lenk=n

求:

        lcm(len1,len2,len3...,lenk)有多少种

显然若其中有几个len为1,并不影响结果,于是条件进一步为:

        len1+len2+len3...+lenk<=n

然后真正巧妙的东西来了。

设lcm=p1^a1*p2^a2*p3^a2..pk^ak  (此处k和上面k无关)

*各质因数的次数来源于len1...lenk中的对应次数最大值

然而我们需要的只是让lcm<=n

如何做到?充要条件是p1^a1+p2^a2...+pk^ak<=n

为什么呢?

        我们让lcm<=n合法,只要设法构造出一组len1...lenk(假设已除去1)即可

        然后我们反过来,我们只要让len1...lenk这样的构造合法,lcm<=n也就成立

根据之前*处,显然对于p1^a1所在的b1..pk^ak所在的bk

        b1>=p1^a1,b2>=p2^a2... bk>=pk^ak

我们并不要求所有b1...bk都满足b1+...+bk<=n,那么只要其最小值<=n,构造就是合法的


然后就变成了背包问题辣,不过是第k件物品有pk^1..pk^ak共ak种权值罢了

-----------------------------------------------------------------------------------------------------------------------------

Code:

#include<iostream> 
#include<cstdio> 
#include<cstring> 
using namespace std; 
typedef long long ll; 
  
const int N=1010; 
  
ll pr[N],tot=0,n; 
bool np[N]; 
ll f[2][N]; 
  
void Pre(){ 
    for(int i=2;i<=N;i++){ 
        if(!np[i]) pr[++tot]=i; 
        for(int j=1;j<=tot&&pr[j]*i<=N;j++){ 
            np[i*pr[j]]=1; 
            if (!(i%pr[j])) break; 
        } 
    } 
} 
  
int main(){ 
//  freopen("1025.in","r",stdin); 
//  freopen("1025.out","w",stdout);  
    Pre(); f[0][0]=1; 
    scanf("%lld",&n); 
    for(int i=1;i<=tot;i++){ 
        memset(f[i&1],0,sizeof(f[i&1])); 
        for(int j=0;j<=n;j++){ 
            f[i&1][j]=f[(i+1)&1][j]; 
            for(int k=pr[i];k<=j;k*=pr[i]) 
                f[i&1][j]+=f[(i+1)&1][j-k]; 
        } 
    }ll ans=0; 
    for(int i=0;i<=n;i++) ans+=f[tot&1][i]; 
    printf("%lld\n",ans); 
    return 0; 
} 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值