题意
有一个长度为N的数组Ai,每个元素可以取1~M中的一个正整数。那么一共有M^N种可能的数组。因为 SHUXK 对数
论有特殊的爱好,所以他立刻想到了下面两个问题:
1. 对于给定的正整数K,有多少个数组Ai满足GCD(A1,A2…An) = K
2. 对于给定的正整数K,有多少个数组Ai满足K|Lcm(A1,A2…An)
(我相信机智的你在看到这道题的英文名称时就已经猜得八九不离十了)当然,对于 SHUXK 来说,只询问一个K的
情况很简单。于是他加强了一下:给定一个范围L~R,对L~R中所有的正整数K都求出答案,并且把它们加起来作为
最终的结果。然后, SHUXK 就不会了……他需要你来帮助他计算出答案。 由于答案可能很大,我们只要求输出答
案对1,000,000,007取模的结果。
( Type = 1时只询问 gcd 的问题, Type = 2时只询问 lcm 的问题)。
T<=500,Type=1时,M<=10^7,Type=2时M<=1000
分析
第一问:
设
f(i)
f
(
i
)
表示
[1,i]
[
1
,
i
]
中的数选出n个来
gcd=1
g
c
d
=
1
的方案数。
那么
f(i) f ( i ) 可以通过容斥来求
不难发现只有 O(n−−√) O ( n ) 个 f(x) f ( x ) 是有用的,所以询问一次的复杂度是 O(m−−√logn) O ( m l o g n )
第二问:
因为m很小,所以我们可以枚举每个k然后分别求方案。
先把k分解质因数,不难发现最多只有4种质因数。
那么我们可以通过容斥来求有多少种方案使得对于每一种质因子至少有一个数满足其对应指数不小于该质因子的指数。
具体来说就是dfs出所有质因子的选择方案,然后求出
[1,m]
[
1
,
m
]
有多少个数满足每一个数对应质因子的指数都小于选出来的质因子指数。
这个也可以通过容斥来求。
具体来说就是有若干个限制,每个限制形如每个数中p的指数不能大于x。
若有一个限制的话数量就是
m−⌊mpx⌋
m
−
⌊
m
p
x
⌋
若有两个限制的话数量就是
m−⌊mpx⌋−⌊mqy⌋+⌊mpxqy⌋
m
−
⌊
m
p
x
⌋
−
⌊
m
q
y
⌋
+
⌊
m
p
x
q
y
⌋
如此类推。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MOD=1000000007;
int n,m,l,r,stack[100005],top,a[10000005],ans,tot,prime[1005],low[1005],T,ty,s1[105],s2[105],t1,t2,sum;
bool not_prime[1005];
void mod(int &x) {x-=x>=MOD?MOD:0;}
int ksm(int x,int y)
{
int ans=1;
while (y)
{
if (y&1) ans=(LL)ans*x%MOD;
x=(LL)x*x%MOD;y>>=1;
}
return ans;
}
void solve1()
{
while (T--)
{
scanf("%d%d%d%d",&n,&m,&l,&r);
top=0;
for (int i=1,last;i<=m;i=last+1) last=m/(m/i),stack[++top]=m/i;
a[1]=1;top--;
while (top)
{
int x=stack[top];top--;
a[x]=ksm(x,n);
for (int i=2,last;i<=x;i=last+1)
{
last=x/(x/i);
mod(a[x]+=MOD-(LL)a[x/i]*(last-i+1)%MOD);
}
}
int ans=0;
for (int i=l,last;i<=r;i=last+1)
{
last=min(r,m/(m/i));
mod(ans+=(LL)a[m/i]*(last-i+1)%MOD);
}
printf("%d\n",ans);
}
}
void dg(int x,int y,int d)
{
if (x>t2) {sum+=(y&1)?-m/d:m/d;return;}
dg(x+1,y,d);
dg(x+1,y+1,d*s2[x]);
}
void dfs(int x,int y)
{
if (x>t1)
{
sum=0;dg(1,0,1);
if (y&1) mod(ans+=MOD-ksm(sum,n));
else mod(ans+=ksm(sum,n));
return;
}
dfs(x+1,y);
s2[++t2]=s1[x];dfs(x+1,y+1);t2--;
}
void solve2()
{
for (int i=2;i<=1000;i++)
{
if (!not_prime[i]) prime[++tot]=i,low[i]=i;
for (int j=1;j<=tot&&i*prime[j]<=1000;j++)
{
not_prime[i*prime[j]]=1;
low[i*prime[j]]=prime[j];
if (i%prime[j]==0) break;
}
}
while (T--)
{
scanf("%d%d%d%d",&n,&m,&l,&r);
ans=0;
for (int i=l;i<=r;i++)
{
t1=t2=0;int tmp=i;
while (tmp>1)
{
int p=low[tmp];s1[++t1]=1;
while (tmp%p==0) tmp/=p,s1[t1]*=p;
}
dfs(1,0);
}
printf("%d\n",ans);
}
}
int main()
{
scanf("%d%d",&T,&ty);
if (ty==1) solve1();
else solve2();
return 0;
}