zoukankan      html  css  js  c++  java
  • 【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;
    }
  • 相关阅读:
    npm、webpack、vue-cli 快速上手版
    jquery 显示和隐藏的三种方式
    jquery好友面板切换
    jquery 事件冒泡
    jquery QQ微博
    C# Thread 参数
    WPF Dispatcher的使用
    UVa 1600 Patrol Robot (BFS最短路 && 略不一样的vis标记)
    HDU 2795 Billboard (线段树单点更新 && 求区间最值位置)
    HDU 1394 Minimum Inversion Number (树状数组 && 规律 && 逆序数)
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793384.html
Copyright © 2011-2022 走看看