BZOJ3930: [CQOI2015]选数

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3930

容斥原理。

令l=(L-1)/k,r=R/k,这样找k的倍数就相当于找1的倍数。

设F[i]为gcd为i的选数情况数,有F[i]=(r/i-l/i)^n-F[i*2]-F[i*3]-......-(r/i-l/i) 这个是除掉全部都一样的情况。

然后如果k在[L,R]之内的话答案要加一,也就是全部都是k的这种情况是可以的。

#include<cstring>
#include<iostream>
#include<cstdio>
#include<map>
#include<cmath>
#include<algorithm>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define maxn 500500
#define inf 2000000000
#define mm 1000000007
using namespace std;
int n,k,l,r,ok,ans,m,L,R,mx,t;
int f[maxn];
int read(){
    int x=0,f=1; char ch=getchar();
    while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
int Pow(int x,int y){
    int ans=1;
    while (y){
        if (y&1) ans=1LL*ans*x%mm;
        x=1LL*x*x%mm;
        y>>=1;
    }
    return ans;
}
int main(){
    n=read(); k=read(); L=read(); R=read(); 
    if (L<=k&&k<=R) ans++;
    L=(L-1)/k; R=R/k;
    mx=R-L;
    down(i,mx,1){
        l=L/i; r=R/i; t=r-l;
        f[i]=(Pow(t,n)-t+mm)%mm;
        for (int j=2*i;j<=mx;j+=i) f[i]=(f[i]-f[j]+mm)%mm;
    }
    printf("%d\n",f[1]+ans);
    return 0;
} 

 

posted on 2016-01-11 12:32  ctlchild  阅读(138)  评论(0编辑  收藏  举报

导航