JZOJ 4586 Ned 的难题【NOIP2016模拟7.7】

Ned 的难题

题目描述

这里写图片描述

输入格式

这里写图片描述

输出格式

这里写图片描述

样例输入

3
4 6 2

样例输出

384

数据范围

这里写图片描述

题解

首先,显然,某个质数 p 对答案的贡献跟一个子序列里这个质数的次数的最小值有关。
其次,序列里的每一个数分解质因数后,大于 107 的素数的次数最多为1,对于这类素数分开讨论就可以了。对于 一个素数 p ,如果连续的k个数都能整除 p ,那么对于p素数来说,这连续的 k 个数对答案的贡献为pk(k+1)2

对于剩下的那些小于 107 的素数分开讨论就可以了,这类的素数不超过1000个。

对于一个小于 107 的素数 p ,建立一个新数组保存每一个数含有素数p的次数。求素数 p <script type="math/tex" id="MathJax-Element-828">p</script>贡献的方法我们可以用一个单调栈随便维护一下就可以了。

Code(Pascal)

const
    mo=1000000009;
    jx=3162;
var
    ss:array[0..1000] of longint;
    f:array[0..jx] of boolean;
    a,zs,d:array[0..50000] of int64;
    n,m,j,k,l,i,o,p:longint;
    ans,kk,gg:int64;
function max(a,b:int64):int64;
    begin
        if a>b then exit(a)
        else exit(b);
    end;
function ksm(cqy,t:int64):int64;
    var
        o:int64;
    begin
        o:=1;
        while t>0 do
        begin
            if t mod 2=1 then o:=(o*cqy) mod mo;
            t:=t div 2;
            cqy:=(cqy*cqy) mod mo;
        end;
        exit(o);
    end;
procedure lj(o:longint);
    var
        i,j,k,l,top:longint;
        p,oo:int64;
    begin
        for i:=1 to n do
        begin
            zs[i]:=0;
            while a[i] mod ss[o]=0 do
            begin
                inc(zs[i]);
                a[i]:=a[i] div ss[o];
            end;
        end;
        top:=2;
        d[1]:=0;
        d[2]:=1;
        p:=zs[1];
        oo:=zs[1];
        for i:=2 to n do
        begin
            inc(top);
            d[top]:=i;
            while (zs[d[top]]<zs[d[top-1]]) and (top>1) do
            begin
                dec(top);
                oo:=oo-(d[top]-d[top-1])*(zs[d[top]]);
                d[top]:=d[top+1];
            end;
            if zs[i]=0 then
            begin
                oo:=0;
                top:=1;
                d[top]:=i;
            end;
            oo:=oo+(i-d[top-1])*zs[i];
            p:=p+oo;
        end;
        ans:=ans*ksm(ss[o],p) mod mo;
    end;
begin
    assign(input,'ned.in'); reset(input);
    assign(output,'ned.out'); rewrite(output);
    readln(n);
    for i:=1 to n do
    begin
        read(a[i]);
        p:=max(p,a[i]);
    end;
    for i:=2 to jx do
    if f[i]=false then
    for l:=i to jx div i do
    f[i*l]:=true;
    for i:=2 to jx do
    if f[i]=false then
    begin
        inc(o);
        ss[o]:=i;
    end;
    ans:=1;
    for i:=1 to o do
    lj(i);
    kk:=1;
    gg:=1;
    for i:=1 to n do
    if a[i]=kk then inc(gg)
    else
    begin
        ans:=ans*ksm(kk,gg*(gg+1) div 2) mod mo;
        kk:=a[i];
        gg:=1;
    end;
    ans:=ans*ksm(kk,gg*(gg+1) div 2) mod mo;
    writeln(ans);
    close(input);
    close(output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值