【递推】BZOJ 3930: [CQOI2015]选数

 

Description

  我们知道,从区间[L,H](L和H为整数)中选取N个整数,总共有(H-L+1)^N种方案。小z很好奇这样选出的数的最大公约数的规律,他决定对每种方案选出的N个整数都求一次最大公约数,以便进一步研究。然而他很快发现工作量太大了,于是向你寻求帮助。你的任务很简单,小z会告诉你一个整数K,你需要回答他最大公约数刚好为K的选取方案有多少个。由于方案数较大,你只需要输出其除以1000000007的余数即可。

Input

  输入一行,包含4个空格分开的正整数,依次为N,K,L和H。

Output

  输出一个整数,为所求方案数。


  这道题有两种做法- -

  1.递推

  我们先设在一段区间[l,r]间选择n个元素,且它们的gcd为k*i的选择方案是f[i]。

  显然,[l,r]内能被k*i整除的数有(R-L+1)^n个(R=r/(i*k),L=l/(i*k))。但是,有一些选择是这种(L,L,L,L,L,L,...L),一共有(R-L+1)种,同时还有最大公约数是k*i的倍数的,我们也要减去。

  得到f[i]=(R-L+1)^n-(R-L+1)-f[i*a](a>=2 && k*i*a<=L-R+1)。

  输出f[1]即可。

  但是还有特殊情况。就是k在[l,r]间,所以这时f[1]++即可。

  2.mobius反演

  公式还是蛮容易的。。

  mobius公式推导:http://lzy-foenix.gitcafe.io/2015/04/09/BZOJ-3930-CQOI2015-%E9%80%89%E6%95%B0/

  关于阀值与μ的推导:http://www.cnblogs.com/Asm-Definer/p/4434601.html

  PoPoQQQ的两者结合:http://blog.csdn.net/popoqqq/article/details/44917831(画质感人- -)

  My Code

 1 #include
 2 #include
 3 #include
 4 #include
 5 
 6 #define mod 1000000007
 7 
 8 #define maxn 100000
 9 
10 using namespace std;
11 
12 long long f[maxn+1];
13 
14 long long qvod(long long x,long long k)
15 {
16     long long ans=1;
17     while(k!=0)
18     {
19         if(k&1)ans=ans*x%mod;
20         x=x*x%mod;
21         k>>=1;
22     }
23     return ans;
24 }
25 
26 int main()
27 {
28     int a,b,k,n;
29     scanf("%d%d%d%d",&n,&k,&a,&b);
30     int l=a/k,r=b/k;
31     if(a%k)l++;
32     for(int i=maxn;i>=1;i--)
33     {
34         int L=l/i,R=r/i;
35         if(l%i)L++;
36         if(l<=r)
37         {
38             f[i]=qvod(R-L+1,n);
39             f[i]=(f[i]-(R-L+1)+mod)%mod;
40             for(int j=i*2;j<=maxn;j+=i)f[i]=(f[i]-f[j]+mod)%mod;
41         }
42     }
43     if(l==1)f[1]++;
44     printf("%lld",(f[1]+mod)%mod);
45     return 0;
46 }
View Code

 

  忽视奇怪的快速幂【递推】BZOJ 3930: [CQOI2015]选数_第1张图片

你可能感兴趣的:(【递推】BZOJ 3930: [CQOI2015]选数)