• jzoj5787 轨道


    Description

    2018年1月31日,152年一遇的超级大月全食在中国高空出现(没看到的朋友真是可惜),小B看到月食,便对月球的轨道产生了兴趣。他上网查重力加速度的公式,公式如下:


    就在这个时候,他想到了一个跟这个差不多的问题,那就是对于以下公式:

    已知n和k,求这n个正整数在都不大于m的情况下有多少种选择方式,使得v为与k互质正整数?
     

    Input

    一行三个正整数n,m,k(意义见题目描述)。

    Output

    输出一个答案,代表方案数。因为答案可能会很大,所以输出方案数mod 10007的值。

    Data Constraint

    数据范围
    对于20%的数据 1<=n,m<=8 k<=100
    对于40%的数据 1<=n<=50 1<=m<=10^6 1<=k<=10^4
    对于70%的数据 1<=n<=100 1<=m<=10^9 1<=k<=10^7
    对于100%的数据 1<=n<=3000 1<=m<=10^9 1<=k<=10^7

    嗯这道题拖了好几天了...

    设dp[i][j]表示枚举到第i个数,这i个数乘积为j的方案数。

    发现j的取值范围太大,数组根本开不下。考虑缩小j的范围。

    发现题目中有关i个数乘积的部分中,有用的只有乘积与k的gcd。

    因此修改dp[i][j]为枚举到第i个数,这i个数的乘积与k的gcd是k的第几个约数。

    考虑转移方程,发现方程即为dp[i][j]=dp[i-1][k]*dp[1][a[j]/a[k]是k的第几个约数]。

    因此只需预处理出dp[1][sth],也就是在1~m中有多少个数与k的gcd为a[sth]。

    枚举的话肯定行不通,要用更快捷的方法。

    考虑容斥原理。

    由于博主太蒟蒻,无法叙述清楚容斥系数,烦请各位大佬自行查看代码...

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #define MOD 10007
    using namespace std;
    int n,m,k,fac[4001],kpri[4001],fsf[4001][4001],mp[10000001];
    int m1,sum;
    int dp[3001][4001];
    void dfs(int cnt,int p_m,int assemble)
    {
        if(cnt>kpri[0]) {sum+=m1/assemble*p_m;return;}
        dfs(cnt+1,p_m,assemble);
        dfs(cnt+1,-p_m,assemble*kpri[cnt]);
    }
    int main()
    {
        freopen("orbits.in","r",stdin);
        freopen("orbits.out","w",stdout);
        scanf("%d%d%d",&n,&m,&k);
        int sqtk=sqrt(k);
        for(int i=1;i<=sqtk;i++)
            if(k%i==0)
            {
                fac[++fac[0]]=i;
                if(k/i>sqtk) fac[++fac[0]]=k/i;
            }
        sort(fac+1,fac+1+fac[0]);
        int tmp=k;
        for(int i=2;i<=sqtk;i++)
        {
            if(tmp==1) break;
            if(tmp%i==0)
            {
                kpri[++kpri[0]]=i;
                while(tmp%i==0) tmp/=i;
            }
        }
        if(tmp!=1) kpri[++kpri[0]]=tmp;
        sort(kpri+1,kpri+1+kpri[0]);
        for(int i=1;i<=fac[0];i++)
        {
            mp[fac[i]]=i;
            sum=0,m1=m/fac[i];
            dfs(1,1,1);
            dp[1][i]=sum%MOD;
        }
        for(int i=1;i<=fac[0];i++)
            for(int j=1;j<=i;j++)
                if(fac[i]%fac[j]==0) fsf[i][++fsf[i][0]]=j;
        for(int i=2;i<=n;i++)
            for(int j=1;j<=fac[0];j++)
            {
                if(fsf[j][0]==0) continue;
                for(int k=1;k<=fsf[j][0];k++)
                    (dp[i][j]+=dp[i-1][fsf[j][k]]*dp[1][mp[fac[j]/fac[fsf[j][k]]]])%=MOD;
            }
        printf("%d
    ",dp[n][fac[0]]);
        return 0;
    }
  • 相关阅读:
    7月17日
    7月16日学习记录
    7月15日学习记录
    git 学习
    投稿相关
    ubuntu16.04 安装以及要做的事情
    python学习使用
    图像相关
    不识别移动硬盘
    深度学习
  • 原文地址:https://www.cnblogs.com/water-radish/p/9465421.html
Copyright © 2020-2023  润新知