题目大意
第i个数是
xai+1−1x−1
求n个数的lcm
结论
(xn−1,xm−1)=x(n,m)−1
可以用辗转相除法来证明。
(xn−1,xm−1)=(xn−xm,xm−1)=(xm∗(xn−m−1),xm−1)
显然
xm
与
xm−1
互质
(xn−1,xm−1)=(xn−m−1,xm−1)
那么我们可以一直让n减m,直到n小于m,然后交换过来,用m不断减n……
可以看做这个过程就是从(n,m)变成(m,n%m)。
边界的情况是m=0。
这就是辗转相除法!
所以得证。
[x1……xn]=Πnk=1(−1)k+1Π1<=y1<y2<……<yk−1<yk<=n(xy1……xyk)
我们可以来理解gcd与lcm的意义。
只看一种质因子,gcd的意义是取min,lcm的意义是取max。
那么其实这个式子可以看做容斥。
实在觉得太难看做容斥,可以考虑计算每个数出现次数,用组合数来算。
具体就是把这n个数都表示成p的次幂(p是一个质数),根据大小排列一下。
那么第i个数的出现次数为
∑i−1j=0Cji−1∗(−1)j
容易证明上式只有i=1时为1,其余情况为0。
因此得出来的是最大值,也就是lcm的意义。
暴力
有了上面的两个结论就可以暴力做了。
选一些数的本质gcd个数很少。
我们维护每种gcd在最终式子的出现情况,每次加入一个ai,就扫一遍已有ai更新,并加入一些新的gcd(可能,不一定产生新的gcd)。
那个分母是x-1可以不管,最后结果除以x-1。
不用考虑没有逆元的问题,出题人说了数据没有这种情况!
如果你实在是很严谨,你可以考虑把x-1除以一个模数,在模模数平方意义下做出的结果再除以一个模数,可能涉及到long long相乘取模。
#include<cstdio>
#include<algorithm>
#include<map>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
map<int,int> f,h;
map<int,bool> g;
const int mo=1000000007;
int b[9010],a[110];
int i,j,k,l,t,n,m,top,tot,ans;
ll x;
int gcd(int a,int b){
return (b?gcd(b,a%b):a);
}
int quicksortmi(ll x,int y){
if (!y) return 1;
int t=quicksortmi(x,y/2);
t=(ll)t*t%mo;
if (y%2) t=(ll)t*(x%mo)%mo;
return t;
}
int main(){
scanf("%lld%d",&x,&n);
fo(i,1,n) scanf("%d",&a[i]),a[i]++;
fo(i,1,n){
tot=top;
fo(j,1,tot) h[b[j]]=0;
fo(j,1,tot){
t=gcd(a[i],b[j]);
if (!g[t]){
g[t]=1;
b[++top]=t;
}
(h[t]+=-f[b[j]])%=(mo-1);
}
t=a[i];
if (!g[t]){
g[t]=1;
b[++top]=t;
}
(h[t]+=1)%=(mo-1);
fo(j,1,top) f[b[j]]+=h[b[j]];
}
ans=1;
fo(i,1,top){
t=(quicksortmi(x,b[i])%mo-1)%mo;
//t=(ll)t=quicksortmi(x-1,mo-2)%mo;
if (f[b[i]]>=0) ans=(ll)ans*quicksortmi(t,f[b[i]])%mo;
else ans=(ll)ans*quicksortmi(quicksortmi(t,-f[b[i]]),mo-2)%mo;
}
ans=(ll)ans*quicksortmi(x-1,mo-2)%mo;
(ans+=mo)%=mo;
printf("%d\n",ans);
//printf("%d %d %d\n",f[1],f[2],f[3]);
}