【bzoj3930】选数 容斥原理+暴力
Description
我们知道,从区间[L,H](L和H为整数)中选取N个整数,总共有(H-L+1)^N种方案。小z很好奇这样选出的数的最大公约数的规律,他决定对每种方案选出的N个整数都求一次最大公约数,以便进一步研究。然而他很快发现工作量太大了,于是向你寻求帮助。你的任务很简单,小z会告诉你一个整数K,你需要回答他最大公约数刚好为K的选取方案有多少个。由于方案数较大,你只需要输出其除以1000000007的余数即可。
Input
输入一行,包含4个空格分开的正整数,依次为N,K,L和H。
Output
输出一个整数,为所求方案数。
Sample Input
2 2 2 4
Sample Output
3
HINT
样例解释
所有可能的选择方案:(2, 2), (2, 3), (2, 4), (3, 2), (3, 3), (3, 4), (4, 2), (4, 3), (4, 4)
其中最大公约数等于2的只有3组:(2, 2), (2, 4), (4, 2)
对于100%的数据,1≤N,K≤10^9,1≤L≤H≤10^9,H-L≤10^5
Sol
首先最重要的条件:\(H-L\)在\(10^5\)以内,这说明区间内\(gcd(i,j)<10^5\),那么我们可以直接枚举gcd是多少,然后进行计算。
具体地,我们把H和L都/=K,这样所求变成了\(gcd(a_1,a_2,...,a_n)=1\)的方案数。
我们设\(f[i]\)表示区间内\(gcd\)为i的方案数,那么\(f[i]\)可以再次通过除以\(i\)然后直接求区间长度的方式解决,但是这样我们会把\(\sum_{i|d}f[d]\)也算上,所以需要把i倍数的d减掉,倒推即可。
本题的三个小细节:
- 如果K在L和R的范围内,那么ans++。
- 如果\(L\%K\)不等于0,那么新的L等于\(L/K+1\),因为原来的L往后一小部分是不合法的,要去掉,内层统计时亦是如此。
- 要减去N个数都相同的方案,因为显然这种方案不成立,具体地,快速幂后面减个len就行。
时间复杂度\(O(nlogn)\)。
Code
#include <cstdio> int N,K,L,R,l,r,M,m,F,f[100005],P=1e9+7; int ksm(int a,int b){int res=1;for(;b;b>>=1,a=1ll*a*a%P) if(b&1) res=1ll*res*a%P;return res;} int main() { scanf("%d%d%d%d",&N,&K,&L,&R); if(L<=K&&K<=R) F++; L=L%K?L/K+1:L/K,R/=K,M=R-L+1; for(int i=M;i;i--) { l=L%i?L/i+1:L/i,r=R/i,m=r-l+1; if(l<r){f[i]=(ksm(m,N)-m+P)%P;for(int j=(i<<1);j<=M;j+=i) f[i]=(f[i]-f[j]+P)%P;} } printf("%d\n",(F+f[1])%P); }
上一篇: Linux特基础的知识(接上一条)
下一篇: Head内常用标签