[CQOI2015]选数

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:
2 2 2 4
输出样例#1:
3

说明

样例解释

所有可能的选择方案:(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

此题有巧解

首先将L/k,R/k,gcd=k/k=1

令f(x)为gcd=x的方案数

F(i)为x能被i整除的方案数

F(i)=∑df(d)    (i|d)

反演得f(d)=∑iμ(i/d)F(i)  (d|i)

f(1)=∑μ(i)F(i)    (1<=i<=H)

=∑μ(i)([r/i]-[(l-1)/i])^n

可知当i>H-L时,[r/i]-[(l-1)/i]等于1或0,所以可以去掉指数

f(1)=∑μ(i)([r/i]-[(l-1)/i])+∑μ(j)([r/j]-[(l-1)/j])^n         (H-L+1<=i<=H,1<=j<=H-L)

因为H-L很小,直接枚举加快速幂搞定,对于左边

∑μ(i)([r/i]-[(l-1)/i])                  (H-L+1<=i<=H)

=∑μ(i)([r/i]-[(l-1)/i])-∑μ(j)([r/j]-[(l-1)/j])     (1<=i<=H,1<=j<=H-L)

右边快速幂,而∑μ(i)([r/i]-[(l-1)/i])可以等价于取一个数,使gcd=1的方案数,显然只有当L=1时+1

复杂度为O((H-L)*log(n))

似乎此题还可以用递推??

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int Mod=1000000007;
 7 typedef long long lol;
 8 bool vis[100001];
 9 lol mu[100001],r,l,n,k,ans;
10 int tot,prime[100001];
11 lol qpow(lol x,lol y)
12 {
13     lol res=1;
14     while (y)
15     {
16         if (y%2==1)
17         {
18             res=(res*x)%Mod;
19         }
20         x=(x*x)%Mod;
21         y=y/2;
22     }
23     return res;
24 }
25 void mobius()
26 {lol i,j;
27 mu[1]=1;
28     for (i=2;i<=r-l;i++)
29     {
30         if (vis[i]==0)
31         {
32             tot++;
33             prime[tot]=i;
34             mu[i]=-1;
35         }
36         for (j=1;j<=tot,i*prime[j]<=r-l;j++)
37          {
38              vis[i*prime[j]]=1;
39              if (i%prime[j]==0)
40              {
41                  mu[i*prime[j]]=0;
42                  break;
43             }
44                  mu[i*prime[j]]=-mu[i];
45          }
46     }
47 }
48 int main()
49 {int i;
50     cin>>n>>k>>l>>r;
51     l=(l+k-1)/k;r=r/k;
52     mobius();
53     for (i=1;i<=r-l;i++)
54     {
55       ans=(ans+mu[i]*qpow(r/i-(l-1)/i,n)%Mod)%Mod;    
56     }
57     if (l==1) ans++;
58     for (i=1;i<=r-l;i++)
59     {
60       ans=(ans-mu[i]*(r/i-(l-1)/i))%Mod;    
61     }
62  cout<<(ans+Mod)%Mod;
63 } 

 

posted @ 2017-08-04 15:23  Z-Y-Y-S  阅读(242)  评论(0编辑  收藏  举报