码迷,mamicode.com
首页 > 其他好文 > 详细

JZOJ 4638 第三条跑道 【NOIP2016提高组A组7.16】

时间:2016-07-18 20:13:35      阅读:540      评论:0      收藏:0      [点我收藏+]

标签:

第三条跑道

该题目的名字是一首歌

题目大意

技术分享
技术分享
技术分享

输入格式

技术分享

输出格式

对于每个询问,单独一行输出答案。

样例输入

5
2 3 4 5 6
3
1 1 5
0 2 3 6
1 2 3

样例输出

32
48

数据范围

技术分享

题解

我们先看一下φ的通式。
技术分享
其中p1, p2……pn为x的所有质因数,x是不为0的整数。
再看一下数据范围,技术分享,这也就意味着ai在任何时刻都满足它的素因子是600以内的,而φ(ai)只跟它的素因子有关。

因为是区间查询/修改,当然是开线段树了。
600以内的素因子有109个,所以我们就种109棵线段树维护每一段区间的含有该素数的ai的个数。(如果y|x,我们就说x含有y
在维护格式的同时,我们也维护这段区间Πri=lφ(ai)ai的欧拉函数的值的积)

我们把通式分成两部分,AB两个部分,如图所示
技术分享

我们把修改时的x分解质因数以后一个一个质因数去更新区间。
当我们给某段区间乘上一个质因数y时(设该区间内有u个数,其中有ky个数含有质因数y),我们分类讨论。

对于那ky个含有质因数y的数,乘上一个y以后,在通式内,A部分乘上了y,因为这ky个数含有y,所以B部分不变,所以这ky个数乘上了y以后对该区间欧拉积(Πri=lφ(ai))的贡献就是乘上yky

对于剩下的那u-ky个不含有素数y的数,它们通式里的的A部分乘上了一个y,因为它们不含有素数y,所以B部分乘上了一个(1-1y),所以其实,它的欧拉函数的值乘上了y*1-1y,化简后可得,它的欧拉函数的值乘上了(y?1),所以这u-ky个不含有素数y的数再乘上了y以后,对该区间欧拉积(Πri=lφ(ai))的贡献就是乘上(y?1)u?ky

综上所述,该区间乘上了素数y以后,它的欧拉积就会乘上(y?1)u?ky*yky,并且乘上了素数y后,该区间的每一个素数都含有了素数y,所以要把u更新一下,就可以了。

懒惰标记下传,更新方法跟上面的一样,至于查询,答案就是对应的多段区间的欧拉函数积的积。

Code(Pascal)

const
    mo=100000007;
var
    bz:array[0..600] of boolean;
    a,ss,ny:array[0..30000] of int64;
    la:array[0..50000,0..109] of longint;
    tr:array[0..50000,0..109] of int64;
    j,k,l,i,oo,p,n,q,pd,x,y,z:longint;
    ans:int64;
function ksm(o,t:int64):int64;
    var
        cqy:int64;
    begin
        cqy:=1;
        while t>0 do
        begin
            if t mod 2=1 then cqy:=cqy*o mod mo;
            t:=t div 2;
            o:=o*o mod mo;
        end;
        exit(cqy);
    end;
procedure jl(o,l,r:longint);
    var
        i,mid:longint;
    begin
        if l=r then
        begin
            tr[o,0]:=a[l];
            for i:=1 to oo do
            if a[l] mod ss[i]=0 then
            begin
                inc(tr[o,i]);
                tr[o,0]:=tr[o,0]*(ss[i]-1) div ss[i];
            end;
            exit;
        end;
        mid:=(l+r) div 2;
        jl(o*2,l,mid);
        jl(o*2+1,mid+1,r);
        tr[o,0]:=tr[o*2,0]*tr[o*2+1,0] mod mo;
        for i:=1 to oo do
        tr[o,i]:=tr[o*2,i]+tr[o*2+1,i];
    end;
procedure gx(o,l,r,ll,rr,k:longint);
    var
        i,mid,ls,rs:longint;
    begin
        if (l=ll) and (r=rr) then
        begin
            la[o,k]:=la[o,k]+1;
            tr[o,0]:=(tr[o,0]*ksm(ss[k]-1,r-l+1-tr[o,k]) mod mo)*ksm(ss[k],tr[o,k]) mod mo;
            tr[o,k]:=r-l+1;
            exit;
        end;
        mid:=(l+r) div 2;
        ls:=o*2;
        rs:=ls+1;
        for i:=1 to oo do
        if la[o,i]>0 then
        begin
            tr[ls,0]:=(tr[ls,0]*ksm(ss[i]-1,mid-l+1-tr[ls,i]) mod mo)
                      *ksm(ss[i],tr[ls,i]) mod mo;
            tr[rs,0]:=(tr[rs,0]*ksm(ss[i]-1,r-mid-tr[rs,i]) mod mo)
                      *ksm(ss[i],tr[rs,i]) mod mo;
            tr[ls,0]:=tr[ls,0]*ksm(ss[i],(mid-l+1)*(la[o,i]-1)) mod mo;
            tr[rs,0]:=tr[rs,0]*ksm(ss[i],(r-mid)*(la[o,i]-1)) mod mo;
            tr[ls,i]:=mid-l+1;
            tr[rs,i]:=r-mid;
            la[ls,i]:=la[ls,i]+la[o,i];
            la[rs,i]:=la[rs,i]+la[o,i];
            la[o,i]:=0;
        end;
        if rr<=mid then gx(ls,l,mid,ll,rr,k)
        else if ll>mid then gx(rs,mid+1,r,ll,rr,k)
        else
        begin
            gx(ls,l,mid,ll,mid,k);
            gx(rs,mid+1,r,mid+1,rr,k);
        end;
        for i:=1 to oo do
        tr[o,i]:=tr[ls,i]+tr[rs,i];
        tr[o,0]:=tr[ls,0]*tr[rs,0] mod mo;
    end;
procedure cx(o,l,r,ll,rr:longint);
    var
        i,mid,ls,rs:longint;
    begin
        if (l=ll) and (r=rr) then
        begin
            ans:=ans*tr[o,0] mod mo;
            exit;
        end;
        mid:=(l+r) div 2;
        ls:=o*2;
        rs:=ls+1;
        for i:=1 to oo do
        if la[o,i]>0 then
        begin
            tr[ls,0]:=(tr[ls,0]*ksm(ss[i]-1,mid-l+1-tr[ls,i]) mod mo)
                      *ksm(ss[i],tr[ls,i]) mod mo;
            tr[rs,0]:=(tr[rs,0]*ksm(ss[i]-1,r-mid-tr[rs,i]) mod mo)
                      *ksm(ss[i],tr[rs,i]) mod mo;
            tr[ls,0]:=tr[ls,0]*ksm(ss[i],(mid-l+1)*(la[o,i]-1)) mod mo;
            tr[rs,0]:=tr[rs,0]*ksm(ss[i],(r-mid)*(la[o,i]-1)) mod mo;
            tr[ls,i]:=mid-l+1;
            tr[rs,i]:=r-mid;
            la[ls,i]:=la[ls,i]+la[o,i];
            la[rs,i]:=la[rs,i]+la[o,i];
            la[o,i]:=0;
        end;
        if rr<=mid then cx(ls,l,mid,ll,rr)
        else if ll>mid then cx(rs,mid+1,r,ll,rr)
        else
        begin
            cx(ls,l,mid,ll,mid);
            cx(rs,mid+1,r,mid+1,rr);
        end;
        for i:=1 to oo do
        tr[o,i]:=tr[ls,i]+tr[rs,i];
        tr[o,0]:=tr[ls,0]*tr[rs,0] mod mo;
    end;
begin
    readln(n);
    for i:=1 to n do
    read(a[i]);
    for i:=2 to 600 do
    if bz[i]=false then
    begin
         inc(oo);
         ss[oo]:=i;
         for l:=i to 600 div i do
         bz[i*l]:=true;
    end;
    jl(1,1,n);
    readln(q);
    for l:=1 to q do
    begin
        read(pd);
        if pd=1 then
        begin
            readln(x,y);
            ans:=1;
            cx(1,1,n,x,y);
            writeln(ans);
        end
        else
        begin
            readln(x,y,z);
            for i:=1 to oo do
            while z mod ss[i]=0 do
            begin
                gx(1,1,n,x,y,i);
                z:=z div ss[i];
            end;
        end;
    end;
end.

JZOJ 4638 第三条跑道 【NOIP2016提高组A组7.16】

标签:

原文地址:http://blog.csdn.net/xianhaoming/article/details/51938814

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!