【[CQOI2015]選數】
阿新 • • 發佈:2019-01-01
這道題自然是可以反演的
按照反演的套路我們先設出兩個函式
\(F(n)\)表示從\([L,H]\)中任選\(N\)個數的最大公約數是\(n\)或者\(n\)的倍數的情況數
\(f(n)\)表示從\([L,H]\)中任選\(N\)個數的最大公約數是\(n\)的情況數
非常顯然的是
\[F(n)=\sum_{n|d}f(d)\]
\[f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)\]
開始反演了
首先我們發現我們求\(f(k)\)並不好求,因為沒有辦法整除分塊
所一我們把\(L/k,H/k\)之後求\(f(1)\)就好了
嗎?
顯然並不行啊
我們考慮一下如果\(L\%k!=0\)
所以如果\(L\%k!=0\)的話,除以\(k\)之後再將\(L+1\)
之後就是如何表示\(F\)了
非常顯然就是
\[F(n)=(\left \lfloor \frac{H}{n}\right \rfloor-\left \lfloor \frac{L-1}{n}\right \rfloor)^N\]
了
\[f(1)=\sum_{i=1}\mu(i)F(i)\]
把\(F(i)\)相等的用整除分塊處理
但是這道題的\(H\)
不能線篩杜教篩總可以了吧,於是就可以用\(O(H^{\frac{2}{3}})\)的複雜度解決這道題
#include<iostream> #include<cstring> #include<cstdio> #include<tr1/unordered_map> #define re register #define maxn 5000001 #define LL long long #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) const int mod=1000000007; using namespace std::tr1; unordered_map<int,int> ma; int p[maxn>>1],f[maxn],mu[maxn]; inline LL quick(int a,int b) { LL S=1; while(b) {if(b&1) S=S*a%mod;b>>=1;a=(LL)a*(LL)a%mod;} return S; } int N,K,L,H,M; int solve(int x) { if(x<=M) return mu[x]; if(ma.find(x)!=ma.end()) return ma[x]; int ans=1; for(re int l=2,r;l<=x;l=r+1) { r=x/(x/l); ans-=solve(x/l)*(r-l+1); } return ma[x]=ans; } int main() { scanf("%d%d%d%d",&N,&K,&L,&H); H/=K; if(L%K==0) L=L/K; else L=L/K+1; M=min(H,5000000); mu[1]=f[1]=1; for(re int i=2;i<=M;i++) { if(!f[i]) p[++p[0]]=i,mu[i]=-1; for(re int j=1;j<=p[0]&&p[j]*i<=M;j++) { f[p[j]*i]=1; if(i%p[j]==0) break; mu[i*p[j]]=-1*mu[i]; } } for(re int i=1;i<=M;i++) mu[i]+=mu[i-1]; LL ans=0;L--; for(re int l=1,r;l<=H;l=r+1) { if(!(L/l)) r=H/(H/l); else r=min(H/(H/l),L/(L/l)); ans=(ans+quick(H/l-L/l,N)*(LL)(solve(r)-solve(l-1))%mod)%mod; } printf("%lld\n",((ans%mod)+mod)%mod); return 0; }