题目
样例输入:
3
4 6 2
样例输出:
384
数据范围:
剖解题意:题目很明了了,这不懂我也没办法。
思路:跟gcd有关,想想gcd方面的东西。
解法:
20%:暴力(从后往前,有利于后面优化)
40%:如果枚举到的一个区间,计算出gcd=1后,可以直接退出了,进入下一个了。
100%(1):gcd的是如何来的?本质是这两个数的公共质因子的个数。
如:6=2*3,8=
23
,公共质因子为2,个数为1(因为6只有一个),所以gcd=2.
所以,我们可以现将所有数分解质因数,然后对于一个质数对某个区间的答案的贡献,其实就是这个区间内这个质数的次数的最小值,所以我们可以用笛卡尔树加上快速幂来解决,时间复杂度O(8nlogn)(注,有常数 8 是因为每个小于 10^7 数最多可以被分成八个不同的质因数)。
然而我并不会…………………..
100%(2):暴力+优化,由40%与20%得来。
我们从后往前暴力时,可以发现有些区间的gcd的值是一样的,且从后往前gcd的值是单调不上升的,并且每一次改变时,gcd至少要除以2.也就是说如果改变至多只有
log2
次,所以我们暴力时可以记录这段相同的区间,然后用快速幂跳过。时间复杂度为
O(nlog2n)
。
代码(方法二)
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;
const int maxn=50005,mo=1e9+9;
ll n,last[maxn],ans,b[maxn];
ll gcd(ll x,ll y)
{
if (y==0) return x;
else return gcd(y,x%y);
}
ll qsm(ll x,ll y)
{
/*if (y==1) return x;
int t=y%2;
ll sum=qsm(x,y/2);
if (t==1) sum=sum*x%mo;*/
//上面是我快速幂时采用递归求,结果爆栈了,以此警戒。还是采用二进制法算了。
ll sum=1; x%=mo;
while (y!=0) {
if (y&1) sum=sum*x%mo;
x=x*x%mo;
y=y>>1;
}
return sum;
}
int main()
{
freopen("ned.in","r",stdin);
freopen("ned.out","w",stdout);
scanf("%lld",&n);
ans=1;
fo(i,1,n){
ll x; int now(i);
scanf("%lld",&x);
ans=ans*x%mo;
b[i]=x;
last[i]=i;
for(int j=i-1;j>0;j=last[j]-1){
b[j]=gcd(b[j],b[now]);
if (b[j]==b[now]) last[now]=last[j];
ans=ans*qsm(b[j],(j-last[j]+1))%mo;
now=j;
}
}
printf("%lld",ans);
fclose(stdin); fclose(stdout);
}