hdu1695(莫比乌斯)或欧拉函数+容斥

题意:求1-b和1-d之内各选一个数组成数对。问最大公约数为k的数对有多少个,数对是有序的。(b,d,k<=100000)


解法1: 这个能够简化成1-b/k 和1-d/k 的互质有序数对的个数。

如果b=b/k。d=d/k,b<=d.欧拉函数能够算出1-b与1-b之内的互质对数。然后在b+1到d的数i,求每一个i在1-b之间有多少互质的数。

解法是容斥,getans函数參数的意义:1-tool中含有rem位置之后的i的质因子的数的个数。

for(int j=rem;j<=factor[i][0];j++)
    ans+=tool/factor[i][j]-getnum(i,tool/factor[i][j],j+1);
这个循环中。ans加的等号后每项表示当前最大的质因子是factor[i][j]的数量,目的是去重。


解法2:莫比乌斯,莫比乌斯数组确实非常实用。事实上也非常easy,mou的位置的含义是,首先假设i有个质因子出现2次或以上。则mou值为0,否则1与-1跟i的质因子奇偶性决定。目的也是容斥。


解法1代码:

/******************************************************
* @author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
//freopen ("in.txt" , "r" , stdin);
using namespace std;

#define eps 1e-8
#define zero(_) (abs(_)<=eps)
const double pi=acos(-1.0);
typedef long long LL;
const int Max=100010;
const LL INF=0x3FFFFFFF;
int a, b, c, d, k;
int factor[Max][20];
bool rem[Max];
LL oular[Max];
void init()
{
    for(int i=1; i<Max; i++)
        oular[i]=i;
    for(LL i=2; i<Max; i++)
    {
        if(!rem[i])
        {
            factor[i][++factor[i][0]]=i;
             oular[i]=i-1;
            for(LL j=i*2; j<Max; j+=i)
            {
                factor[j][++factor[j][0]]=i;
                rem[j]=1;
                oular[j]=oular[j]*(i-1)/i;
            }
        }
    }
    for(int i=1; i<Max; i++)
        oular[i]=oular[i]+oular[i-1];
}
LL getnum(int i,int tool,int rem)
{
    int ans=0;
    for(int j=rem;j<=factor[i][0];j++)
    ans+=tool/factor[i][j]-getnum(i,tool/factor[i][j],j+1);
    return ans;
}
int main()
{
    int t;
    cin>>t;
    init();int kk=1;
    while(t--)
    {
        cin>>a>>b>>c>>d>>k;
        printf("Case %d: ",kk++);
        if(k==0)
        {
            cout<<"0
";
            continue;
        }
        b/=k;
        d/=k;
        if(b>d)swap(b,d);
        LL ans=oular[b];
        for(int i=b+1;i<=d;i++)
        {
            ans+=b-getnum(i,b,1);
        }
        cout<<ans<<endl;
    }
    return 0;
}
解法2代码:
/******************************************************
* @author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
//freopen ("in.txt" , "r" , stdin);
using namespace std;

#define eps 1e-8
#define zero(_) (abs(_)<=eps)
const double pi=acos(-1.0);
typedef long long LL;
const int Max=100010;
const LL INF=0x3FFFFFFF;
int a, b, c, d, k;
bool rem[Max];
int mou[Max];
void init()
{
    mou[1]=1;
    for(LL i=2; i<Max; i++)
    {
        if(!rem[i])
        {
            mou[i]=i;
            for(LL j=i*2; j<Max; j+=i)
            {
                rem[j]=1;
                mou[j]=i;
            }
        }
    }
    for(int i=2; i<Max; i++)
    {
        if(i/mou[i]%mou[i]==0) mou[i]=0;
        else mou[i]=-mou[i/mou[i]];
    }
}
int main()
{
    int t;
    cin>>t;
    init();
    int kk=1;
    while(t--)
    {
        cin>>a>>b>>c>>d>>k;
        printf("Case %d: ",kk++);
        if(k==0)
        {
            cout<<"0
";
            continue;
        }
        b/=k;
        d/=k;
        if(b > d)swap(b,d);
        long long ans1 = 0;
        for(int i = 1; i <= b; i++)
            ans1 += (long long)mou[i]*(b/i)*(d/i);
        long long ans2 = 0;
        for(int i = 1; i <= b; i++)
            ans2 += (long long)mou[i]*(b/i)*(b/i);
        ans1 -= ans2/2;
        cout<<ans1<<endl;
    }
    return 0;
}


原文地址:https://www.cnblogs.com/bhlsheji/p/5182360.html