妙啊
这个题一上来就想的是莫比乌斯反演:
但是看到r的范围发现前缀和不能处理于是不能分块于是时间复杂度为( O(rlog_2n) )于是GG。(其实是可以处理的但是我不会比较麻烦,而且复杂度高所以没写,方法详见PoPoQQQ大爷blog http://blog.csdn.net/popoqqq/article/details/44917831)
这时注意到r-l的范围看起来很可做,所以考虑复杂度与len有关的算法。
这里有一个性质,当a集合不全部相等时( gcd(a_1,a_2...,a_n)=k,kleq a_{max}-a_{min} )。
证明:设( {b_1,b_2...,b_n}={frac {a_1} {k},frac {a_2} {k},...,frac {a_n} {k},} ),因为不全部相等,所以( b_{max}-b_{min} geq 1 ),所以( (b_{max}-b_{min})*k=a_{max}-a_{min}geq k )
首先,( l=(l-1)/k,r=r/k )把问题转换为在新的( (l,r) )范围内求( gcd==1 ) 的方案数(注意以下的l和r都是新的范围);
设( f[i] )为gcd为i时的方案数,可以求出gcd为i的倍数是的方案数( sum=(left lceil r/i
ight
ceil-left lceil l/i
ight
ceil)^n-(left lceil r/i
ight
ceil-left lceil l/i
ight
ceil) ),减去的是集合内数字全部相等的方案个数。那么( f[i]=sum - sum_{i|j}^{jleq len} f[j] )。可以选择从后往前递推。
时间复杂度...理论上是( O(lenlog_2len) )或者 ( O(lenlog_2n) ),但是调和级数和快速幂的复杂度我不知道怎么加(躺
#include<iostream>
#include<cstdio>
using namespace std;
const int N=100005,mod=1e9+7;
int n,k,l,r,len,p,f[N];
int ksm(int a,int b)
{
int r=1;
while(b)
{
if(b&1)
r=(long long)r*a%mod;
a=(long long)a*a%mod;
b>>=1;
}
return r;
}
int main()
{
scanf("%d%d%d%d",&n,&k,&l,&r);
if(l<=k&&r>=k)
p=1;
l=(l-1)/k,r=r/k,len=r-l;
for(int i=len;i>=1;i--)
{
int x=l/i,y=r/i;
f[i]=(ksm(y-x,n)-y+x+mod)%mod;//减去的是区间全部相等
for(int j=i*2;j<=len;j+=i)
f[i]=((f[i]-f[j])%mod+mod)%mod;
}
printf("%d
",f[1]+p);
return 0;
}