CQOI2015 選數
阿新 • • 發佈:2018-12-01
粘題目描述:
我們知道,從區間[L,H](L和H為整數)中選取N個整數,總共有(H-L+1)^N種方案。
小z很好奇這樣選出的數的最大公約數的規律,他決定對每種方案選出的N個整數都求一次最大公約數,以便進一步研究。
然而他很快發現工作量太大了,於是向你尋求幫助。
你的任務很簡單,小z會告訴你一個整數K,你需要回答他最大公約數剛好為K的選取方案有多少個。由於方案數較大,你只需要輸出其除以1000000007的餘數即可。
題解:
容斥+遞推。如果我們在區間[l,r]種任取n個不全相同的數時,他們的gcd一定<=r-l+1(貝祖)。
然後就很好搞了,l=(l+k-1)/k,h=h/k。
然後f[ i ]表示合法區間內選n個數不全相同且gcd==i的方案。
容斥之前是x^n-x,然後逆向處理即可。
程式碼:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MOD 1000000007 #define N 100050 #define ll long long int n,k,l,h; ll f[N]; ll fastpow(ll x,int y) { ll ret = 1ll; while(y) { if(y&1)ret=ret*x%MOD; x=x*x%MOD; y>>=1; } return ret; } int main() { scanf("%d%d%d%d",&n,&k,&l,&h); l=(l+k-1)/k,h=h/k; for(int i=1;i<=(h-l+1);i++) { int x = (h/i)-((l+i-1)/i)+1; f[i]=fastpow(x,n)-x; } for(int i=(h-l+1);i>=1;i--) {for(int j=2;i*j<=(h-l+1);j++) { f[i]=(f[i]-f[i*j]+MOD)%MOD; } } printf("%lld\n",f[1]+(l==1)); return 0; }