洛谷 [CQOI2015]選數 解題報告
[CQOI2015]選數
題目描述
我們知道,從區間\([L,H]\)(\(L\)和\(H\)為整數)中選取\(N\)個整數,總共有\((H-L+1)^N\)種方案。
小\(z\)很好奇這樣選出的數的最大公約數的規律,他決定對每種方案選出的\(N\)個整數都求一次最大公約數,以便進一步研究。然而他很快發現工作量太大了,於是向你尋求幫助。
你的任務很簡單,小\(z\)會告訴你一個整數\(K\),你需要回答他最大公約數剛好為\(K\)的選取方案有多少個。由於方案數較大,你只需要輸出其除以\(1000000007\)的餘數即可。
輸入輸出格式
輸入格式:
輸入一行,包含\(4\)個空格分開的正整數,依次為\(N\)
輸出格式:
輸出一個整數,為所求方案數。
說明
對於\(100\%\)的資料,\(1 \le N, K \le 10^9\),\(1 \le L \le H \le 10^9\),\(H-L \le10^5\)
暴力反演一波你會發現要求這個式子
\[\sum_{d=1}^{\lfloor\frac{r}{k}\rfloor}\mu(d)(\lfloor\frac{\lfloor\frac{r}{k}\rfloor}{d}\rfloor-\lfloor\frac{\lceil\frac{l}{k}\rceil-1}{d}\rfloor)\]
需要使用杜教篩,不想學,發現還有一個神仙的\(DP\)
令\(r=\lfloor\frac{r}{k}\rfloor,l=\lceil\frac{l}{k}\rceil\)
問題等價於問互質的方案數
引理:區間\([l,r]\)任意兩個不相等數的最大公約數的大小不會超過\(r-l\)
證明:取任意互質的數\(a,b\),將它們同乘\(m\),而\(r-l\)取最小值時\((b-a)\times m \ge m\),得證
(證明是從別處抄的,說實話不太懂QAQ)
設\(dp_{i}\)代表以\(i\)為最大公約數的數量,且所選的數不全相等。
考慮\(g_i\)為\(i\)為約數的數量,同樣也是所選的不全相等。
(不全相等是處於統計方便考慮)
顯然
\[g_i=(\lfloor\frac{r}{i}\rfloor-\lfloor\frac{l-1}{i}\rfloor)^n-(\lfloor\frac{r}{i}\rfloor-\lfloor\frac{l-1}{i}\rfloor)\]
根據容斥原理
\[dp_i=g_i-\sum_{i|d}^rdp_d\]
注意要特判\(l=1\),因為這個時候可以全相等
Code:
#include <cstdio>
#define ll long long
const int N=1e5+10;
const ll mod=1e9+7;
ll n,k,l,r;
ll dp[N];
ll quickpow(ll d,ll k)
{
ll f=1;
while(k)
{
if(k&1) f=f*d%mod;
d=d*d%mod;
k>>=1;
}
return f;
}
int main()
{
scanf("%lld%lld%lld%lld",&n,&k,&l,&r);
l=(l-1)/k+1,r=r/k;
for(ll i=1;i<=r-l;i++)
{
ll cnt=(r/i-(l-1)/i);
dp[i]=quickpow(cnt,n)-cnt;
}
for(ll i=r-l;i;i--)
for(ll j=i<<1;j<=r-l;j+=i)
(dp[i]-=dp[j])%=mod;
printf("%lld\n",(dp[1]+(l==1)+mod)%mod);
return 0;
}
2018.10.20