• 【BZOJ1025】游戏(SCOI2009)-数论+背包DP


    测试地址:游戏
    做法:本题需要用到数论+背包DP。
    注意到题目中所给的是一个置换,一个置换中会有若干个循环,而题目中的排数就是这些循环长度的LCM+1,所以问题等价于求若干个和为N的数,它们的LCM有多少种。
    注意到1对LCM不产生任何影响,所以这若干个数的和只需要N即可(因为剩下的可以用1去填)。而对于一些数,它们的LCM为各个质数在这些数中出现的最大次幂之积,我们注意到选几个合数的乘积是没有用的,因为它总是能被拆成LCM等价,但是和更小的质数幂的形式,于是现在的问题就是求取一些质数幂,使得它们的和N,能组合成多少种LCM。那么我们令f(i,j)为考虑了前i种质数,和为j的方案数,我们发现这就是一个背包DP,状态转移方程很容易写出,于是我们就完成了这一题。
    (我校提高组模拟赛出了这题,我居然现在看了题解才会做,我好弱啊……)
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n,prime[1010]={0};
    ll f[1010]={0};
    bool vis[1010]={0};
    
    void calc_prime()
    {
        prime[0]=0;
        for(int i=2;i<=n;i++)
        {
            if (!vis[i]) prime[++prime[0]]=i;
            for(int j=1;j<=prime[0]&&i*prime[j]<=n;j++)
            {
                vis[i*prime[j]]=1;
                if (i%prime[j]==0) break;
            }
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        calc_prime();
    
        f[0]=1;
        for(int i=1;i<=prime[0];i++)
        {
            for(int j=n;j>=0;j--)
            {
                int k=prime[i];
                while(k<=j)
                {
                    f[j]+=f[j-k];
                    k*=prime[i];
                }
            }
        }
        ll ans=0;
        for(int i=0;i<=n;i++)
            ans+=f[i];
        printf("%lld",ans);
    
        return 0;
    }
  • 相关阅读:
    [翻译] M13ProgressSuite
    控制器转场动画详解
    [翻译] SIAlertView
    隐藏导航栏之后支持手势退回上一个控制器
    UIView的无损截图
    [翻译] UIColor-uiGradientsAdditions
    简化通知中心的使用
    Java Web应用的开发环境配置
    StartUML的基础的使用,用例图,序列图
    SQLyog图形化l数据库的操作和学习
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793384.html
Copyright © 2020-2023  润新知