• F


    F - Tmutarakan Exams

    题意 : 从 < = S 的 数 中 选 出 K 个 不 同 的 数 并 且 gcd > 1 。求方案数。
     
    思路 :记 录 一 下 每 个 数 的 倍 数 vector 存 储 ,最后从 2 开始 遍历 一遍每个数 ,从 他的倍数中 挑选 k个 组合数求解。
     
    但是会有重复,因为 比如 K=2,S=15时 , 2倍数 : 2  ,4 , 6,  8, 10,  12, 14 ,   挑出了 这种情况 6 ,12,然后
     
    从3的倍数 : 3, 6 ,9,12 ,15, 也选出了 6, 12 这种情况。所以产生重复计数 ,去重,通过他们的最小公倍数 6
     
    6的倍数 : 6, 12, 去掉 即可。 恰好符合莫比乌斯函数的相反数 作为系数。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define maxn 1234
    vector<ll>p[55];
    bool vis[maxn+10];
    int prime[maxn+10],mu[maxn+10];
    ll s,k,c[33][33],ans,len;
    void init()
    {
        for(int i=0; i<=30; i++)c[i][0]=1;
        for(int i=1; i<=30; i++)
            for(int j=1; j<=i; j++)
                c[i][j]=c[i-1][j-1]+c[i-1][j];
    }
    void getphi()
    {
        int cnt=0;
        mu[1]=1;
        for(int i=2; i<maxn; i++)
        {
            if(!vis[i])
            {
                prime[++cnt]=i;
                mu[i]=-1;
            }
            for(int j=1; j<=cnt&&i*prime[j]<maxn; j++)
            {
                vis[i*prime[j]]=1;
                if(i%prime[j]==0)
                {
                    mu[i*prime[j]]=0;
                    break;
                }
                else mu[i*prime[j]]=-mu[i];
            }
        }
    }
    int main()
    {
        init();
        getphi();
        scanf("%lld%lld",&k,&s);
        for(int i=2; i<=s; i++)
            for(int j=2; j<=i; j++)
                if(i%j==0)p[j].push_back(i);
        for(int i=2; i<=s; i++)
        {
            len=p[i].size();
            if(len<k)continue;
            ans+=(-mu[i]*c[len][k]);
        }
        if(ans>10000)printf("10000
    ");
        else printf("%lld
    ",ans);
        return 0;
    }
    

      直接进行计数  dp[ i ] [ j ] [ k ] 前 i 个 数 选 了 j 个 数, gcd 为 k 的 方 案 数.

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define maxn 65
    ll dp[maxn][maxn][maxn],ans;
    int k,s;
    int main()
    {
        scanf("%d%d",&k,&s);
        for(int i=0; i<=s; i++)dp[i][1][i]=1;
        for(int i=1; i<s; i++)
            for(int j=1; j<=min(k,i); j++)
                for(int z=1; z<=s; z++)
                {
                    dp[i+1][j][z]+=dp[i][j][z];
                    dp[i+1][j+1][__gcd(i+1,z)]+=dp[i][j][z];
                }
        for(int i=2; i<=s; i++)
            ans+=dp[s][k][i];
        if(ans>10000)printf("10000
    ");
        else printf("%lld
    ",ans);
        return 0;
    }
    

      

  • 相关阅读:
    不断学习和思考让自己成长、过得充实快乐!
    先制订个能力提升计划
    如何删除SQL Server下注册的服务器
    [转摘] 我的同学聚会--性格决定命运
    如何提高阅读速度2
    Oracle IW,WW的区别
    想象5年后的你(很多人看了很受启迪!)
    女要富养
    5年内买车买房(理财篇)
    [转摘] 从月薪3500到身价700万 我在上海的奋斗岁月
  • 原文地址:https://www.cnblogs.com/SDUTNING/p/10261612.html
Copyright © 2020-2023  润新知