1. 程式人生 > >bzoj 2818 Gcd(莫比烏斯+gcd(a,b)=d) 經典

bzoj 2818 Gcd(莫比烏斯+gcd(a,b)=d) 經典

2818: Gcd

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 1566  

Description

給定整數N,求1<=x,y<=N且Gcd(x,y)為素數的
數對(x,y)有多少對.

Input

一個整數N

Output

如題

Sample Input

4

Sample Output

4

HINT

hint

對於樣例(2,2),(2,4),(3,3),(4,2)


1<=N<=10^7

題意:給一個正整數 N,其中1<=N<=10^7,求使得 gcd(x,y)為質數的 (x,y)對的個數,1<=x,y<=n

分析:莫比烏斯反演,十分的巧妙。

GCD(a,b)的題十分經典。GCD(a,b)=d   (d是素數),但是思想卻是相同的。

設f(d) = GCD(a,b) = d的種類數 ;

F(n) 為GCD(a,b) = d 的倍數的種類數,GCD(a,b)%d==0;

即 :F(x) = (N/x)*(N/x);//N中是x的倍數的個數,然後組合

則f(x) = sigma( mu[d/x]*F(d), d|n )

由於d = 1 所以f(1) = sigma( mu[d]*F(p*d) ) = sigma( mu[d]*(N/pd)*(N/pd) );   p為列舉的素數;p*d<N; (優化!否則會超時)

so....

初探莫比烏斯。還有很多不是很懂。跟進中。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 1e7+10;
typedef long long LL;

//LL F[MAXN],f[MAXN];
LL pri[MAXN],pri_num;
LL mu[MAXN];//莫比烏斯函式值
bool vis[MAXN];

void mobius(int N)  //篩法求莫比烏斯函式
{
    pri_num = 0;//素數個數
    memset(vis, false, sizeof(vis));
    vis[1] = true;
    mu[1] = 1;
    for(int i = 2; i <=N; i++)
    {
        if(!vis[i])
        {
            pri[pri_num++] = i;
            mu[i] = -1;
        }
        for(int j=0; j<pri_num && i*pri[j]<N ; j++)
        {
            vis[i*pri[j]]=true;//標記非素數
            //eg:i=3,i%2,mu[3*2]=-mu[3]=1;----;i=6,i%5,mu[6*5]=-mu[6]=-1;
            if(i%pri[j])mu[i*pri[j]] = -mu[i];
            else
            {
                mu[i*pri[j]] = 0;
                break;
            }

        }
    }
}

int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    LL n;
    mobius(10000000);
    while(~scanf("%lld",&n))
    {
        LL ans = (LL)0;
        for(LL i=0; pri[i]<=n; i++)
        {
            for(LL j=1; j<=n/pri[i]; j++)
                ans+=(LL)(mu[j]*((n/pri[i])/j)*((n/pri[i])/j));
        }
        printf("%lld\n",ans);
    }
    return 0;
}


我的程式碼跑了7秒。。。學長的程式碼跑了6秒。。。僅供參考

 /* Language: C++
    Result: Accepted
    Time:6432 ms
    Memory:167288 kb
****************************************************************/
 
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
using namespace std;
 
typedef long long LL;
const int maxn = 1e7+1;
bool s[maxn];
int prime[maxn],len = 0;
int mu[maxn];
int g[maxn];
int sum1[maxn];
void  init()
{
    memset(s,true,sizeof(s));
    mu[1] = 1;
    for(int i=2; i<maxn; i++)
    {
        if(s[i] == true)
        {
            prime[++len]  = i;
            mu[i] = -1;
            g[i] = 1;
        }
        for(int j=1; j<=len && (long long)prime[j]*i<maxn; j++)
        {
            s[i*prime[j]] = false;
            if(i%prime[j]!=0)
            {
                mu[i*prime[j]] = -mu[i];
                g[i*prime[j]] = mu[i] - g[i];
            }
            else
            {
                mu[i*prime[j]] = 0;
                g[i*prime[j]] = mu[i];
                break;
            }
        }
    }
    for(int i=1; i<maxn; i++)
        sum1[i] = sum1[i-1]+g[i];
}
 
int main()
{
    int a;
    init();
    while(scanf("%d",&a)>0)
    {
        LL sum = 0;
        for(int i=1,la = 0 ; i<=a; i = la+1)
        {
            la = a/(a/i);
            sum = sum + (long long)(sum1[la] - sum1[i-1])*(a/i)*(a/i);
        }
        printf("%lld\n",sum);
    }
    return 0;
}

網上有其他的解法。。。還快些(5秒)

/**************************************************************
    Problem: 2818
    Language: C++
    Result: Accepted
    Time:5220 ms
    Memory:128224 kb
****************************************************************/
 
#include<bits/stdc++.h>
#define clr(a,x) memset(a,x,sizeof(a))
#define rep(i,l,r) for(int i=l;i<r;i++)
typedef long long ll;
using namespace std;
// 尤拉函式
int read()
{
    char c=getchar();
    int ans=0,f=1;
    while(!isdigit(c)){
        if(c=='-') f=-1;
        c=getchar();
    }
    while(isdigit(c)){
        ans=ans*10+c-'0';
        c=getchar();
    }
    return ans*f;
}
const int maxn=10000009;
bool p[maxn];
ll f[maxn];
int s[maxn],cnt,n;
void getphi()
{
    rep(i,1,n+1) f[i]=i;
    rep(i,2,n+1){
        if(f[i]==i){
            for(int j=i;j<=n;j+=i){
                f[j]=f[j]/i*(i-1);
            }
        }
    }
    rep(i,2,n+1) f[i]+=f[i-1];
}
void getsushu()
{
    clr(p,-1);
    p[1]=0;
    rep(i,2,(n>>1)+1){
        if(p[i]){
            for(int j=i<<1;j<=n;j+=i){
                p[j]=0;
            }
        }
    }
    rep(i,2,n+1){
        if(p[i]){
            s[cnt++]=i;
        }
    }
}
int main()
{    
    n=read();
    getphi();
    getsushu();
    ll ans=0;
    rep(i,0,cnt){
        ans+=f[n/s[i]]*2-1;
    }
    printf("%lld\n",ans);
    return 0;
}


mada...mada...!!!奮鬥

相關推薦

bzoj 2818 Gcd(+gcd(a,b)=d) 經典

2818: Gcd Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1566   Description 給定整數N,求1<=x,y&l

BZOJ 2820 YY的GCD 反演

cstring std swap cst pac lap Go hint name 2820: YY的GCD Description 神犇YY虐完數論後給傻×kAc出了一題給定N, M,求1<=x<=N, 1<=y<=

BZOJ 2820: YY的GCD [反演]

題解: 和上一題相同的函式:   為滿足且和的的對數   為滿足且和的的對數 顯然,反演後得到   可以列舉每一個質數,套用上一題的做法,p相當於k,d*p也就是p的倍數了...很像上一題我WT1中的式子   其實d只要列舉到min(

Gcd HYSBZ - 2818反演)

Gcd  HYSBZ - 2818  給定整數N,求1<=x,y<=N且Gcd(x,y)為素數的 數對(x,y)有多少對.   Input 一個整數N Output 如題 Sample Input 4 Sample O

BZOJ 2820 YY的GCD 反演

由於這道題比較鬼畜,而且公式巨難打出,所以我粘了兩頁PoPoQQQ的PPT orz,並對其中一些部分解釋一下 最下面的公式就是換了一種列舉的方式,其中u括號裡的東西就是把d變成T/p,其中p|T的

【bzoj2820】YY的GCD 反演

spa tex 給定 void fin include ans iostream while YY的GCD Description 神犇YY虐完數論後給傻×kAc出了一題 給定N, M,求1<=x<=N, 1<=y<=M且g

luogu2257 YY的GCD——反演

注意一下處理字首和的時候的trick #include <bits/stdc++.h> using namespace std; #define N 10000005 bool vis[N

YY的gcd[反演模板題]

YY的gcd啊,,題意如下; 多組資料 每組資料給出n,m,k; 求1<=i<=n,1<=j<=m,gcd(i,j)=k;的對數。 資料數最高為10000,n,m<=10000000 毒瘤資料。 根據上文所說,莫比烏斯反演最重要的第一步是找準

hdu1695-GCD-反演入門

這裡F(X)為挑選數目為有多少對滿足 gcd(x,y)==e的倍數gcd(x,y)==e的倍數。 並且 F(x)滿足第二張圖片 (即F(n)為gcd為n的倍數的對數,這個答案等於所有f(d)

hdu GCD(反演+一點學習筆記)

GCD Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 15999  &n

HihoCoder - 1867: GCD (容斥)

rip air mut sat ins isf contains push hoc Sample Input 6 1 6 2 5 3 4 Sample Output 10 You are given a {1, 2, ..., n}-permutation a

luogu2658 GCD(反演/歐拉函數)

for 初始化 urn 發現 sin org turn 素數 cst link 給定整數N,求1<=x,y<=N且Gcd(x,y)為素數的數對(x,y)有多少對. 1<=N<=10^7 (1)莫比烏斯反演法 發現就是YY的GCD,左轉YY的GCD粘過

luogu2257 YY的GCD--反演

初始 lin lld cti cst scanf ret href show link 給定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)為質數的(x, y)有多少對 多組數據T = 10000 N, M <= 1000000

bzoj 1101 Zap —— 反演

div spa targe ini bsp cstring bool con blank 題目:https://www.lydsy.com/JudgeOnline/problem.php?id=1101 直接莫比烏斯反演。 代碼如下: #include<cstdio

BZOJ 2818 GCD 【歐拉函數 || 反演】

true names namespace sin () 莫比烏斯反演 lse tps lin 傳送門:https://www.lydsy.com/JudgeOnline/problem.php?id=2818 2818: Gcd Time Limit: 10 Sec M

BZOJ 2818 Gcdgcd(x,y)為素數/尤拉函式/反演)

題目連結: BZOJ 2818 Gcd 題意: x∈[1,N],y∈[1,N],gcd(x,y)=素數的有序對(x,y)的對數。 分析: 對於一個素數p,如果gcd(x,y)=p,那麼相當於x

反演入門 HDOJ 1695:GCDBZOJ 2301: [HAOI2011]Problem b

下面我所說的都基於上面這篇部落格的內容。 莫比烏斯反演有兩種形式(mu表示莫比烏斯函式): HDOJ1695 GCD 求1<=x<=n,1<=y<=m中gcd(x,y)==k的(x,y)組數,注意(a,b)和(b,a)視為同一情況。 相當於計算

CO-PRIME(初探 )NYOJ1066(經典gcdab)=1

put size 兩個 test hat ott == clas otto CO-PRIME 時間限制:1000 ms | 內存限制:65535 KB 難度:3 描寫敘述 This problem is so easy! Can you solve it

SPOJ - PGCD Primes in GCD Table(反演)

cnblogs -s def problems 前綴和 ret mage () eof http://www.spoj.com/problems/PGCD/en/ 題意: 給出a,b區間,求該區間內滿足gcd(x,y)=質數的個數。 思路: 設f(n)為 gc

hdu 1695 GCD入門)

技術分享 sin urn cas str 由於 ons pre () 題意:求a<=x<=b ,x<=y<=d,中gcd(x,y)==k的數對個數 思路:題目可以轉化成求1<=x<=b/k,1<=y<=d/k中gcd(x,y)