1. 程式人生 > >F - Tmutarakan Exams URAL - 1091 -莫比烏斯函數-容斥 or DP計數

F - Tmutarakan Exams URAL - 1091 -莫比烏斯函數-容斥 or DP計數

strong get rime oid ofo lld 們的 else max

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\n");
    else printf("%lld\n",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\n");
    else printf("%lld\n",ans);
    return 0;
}

  

F - Tmutarakan Exams URAL - 1091 -莫比烏斯函數-容斥 or DP計數