Ned 的难题

题目

这里写图片描述
样例输入:
这里写图片描述
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);
}

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值