hdu 4135 容斥

题意:求解区间a~b与n互质数的个数

题解:转化为1~b与n互质数减去1~a与n互质数的个数,典型的容斥。(由于这里数据范围太大,莫比乌斯就不适用了,直接用容斥枚举质数的组合,负责都根号n)

 

补充:2017.8.18 多校的容斥没写出来,整理一下。一般容斥的思路,求解逆问题。这道题目的逆问题就是不与n互质的数。这里有一个点,我们判断两个数是否互素,只要看把这两个

数唯一分解之后有没有相同的素因子。

ac代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
typedef long long ll;
ll a,b,n;
//ll num[100001],vis[100001];
vector<ll>flag;
vector<ll>deg;
ll prime[100001];
void deal()
{
    int ret=0;
    flag.clear();
    deg.clear();
    for(int i=2;i*i<=n;i++)//得到n的素因子
    {
        if(n%i==0)
        {
            prime[ret++]=i;
            while(n%i==0) n/=i;
        }
    }
    if(n>1) prime[ret++]=n;

for(int i=1;i<(1<<ret);i++) { ll cnt=0; ll temp=1; for(int j=0;j<ret;j++) { if(i&(1<<j)) { cnt++; temp*=prime[j]; } } // cout<<temp<<' '; flag.push_back(cnt); deg.push_back((b/temp)-((a-1)/temp));// 这个细节注意一下,区间的开闭,,错了好几次! } } int main() { int t,Case=0; scanf("%d",&t); while(t--) { scanf("%lld %lld %lld",&a,&b,&n); deal(); // cout<<endl; ll ans=0; int len=flag.size(); for(int i=0;i<len;i++) { //if(flag[i]==0) continue; if(deg[i] > b) break; if(flag[i]%2) ans+=deg[i]; else ans-=deg[i]; } ll zz=b-a+1; printf("Case #%d: %lld\n",++Case,zz-ans); } return 0; }

 

posted @ 2017-08-10 10:04  猪突猛进!!!  阅读(150)  评论(0)    收藏  举报