【递推】[CQOI2015] 选数
这个递推实在是让我感到无奈
实际上就是先计算出在L和R的区间中有多少个数有因数K 然后
F[i] 表示的就是在L和R中选出N个数最大公因数是i*K 的方案数
然后
_LL LL = (N_L - 1) / i + 1;
_LL RR = N_R / i;
_LL Len = RR - LL + 1;
这几句话的意思就是算出在N_L 和 N_R的范围内有多少个数有因数 i * K 然后
F[i] = Pow(Len, N) - Len;
减去Len的原因是因为有Len种情况是N个都选择自己,那么最大公因数就是自己而不是i * K了
然后剪去所有的非法情况就行了
#include <bits/stdc++.h>
using namespace std;
typedef long long _LL;
const _LL MOD = 1e9+7;
const _LL MAXN = 100000;
_LL Pow(_LL n, _LL r){
_LL ret = 1;
n %= MOD;
while(r){
if(r & 1)
ret = ret * n % MOD;
n = n * n % MOD;
r >>= 1;
}
return ret;
}
_LL F[MAXN+10];
_LL work(_LL N, _LL K, _LL L, _LL R){
_LL N_L = (L - 1) / K + 1;
_LL N_R = R / K;
for(int i=MAXN;i>=1;i--){
_LL LL = (N_L - 1) / i + 1;
_LL RR = N_R / i;
_LL Len = RR - LL + 1;
if(Len > 0){
F[i] = Pow(Len, N) - Len;
if(F[i] < 0) F[i] += MOD;
for(int j=i*2;j<=MAXN;j+=i){
F[i] -= F[j];
if(F[i] < 0)
F[i] += MOD;
}
}
}
if(N_L == 1) F[1] ++;
return F[1] % MOD;
}
int main(){
_LL N, K, L, H;
cin>>N>>K>>L>>H;
cout<<work(N,K,L,H)<<endl;
return 0;
}