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; }