ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P3747 [六省联考 2017] 相逢是问候

2022-06-03 19:00:41  阅读:154  来源: 互联网

标签:六省 log 13700558 ll mi varphi tot P3747 联考


Problem:

题目描述

Informatik verbindet dich und mich.
信息将你我连结。

B 君希望以维护一个长度为 \(n\) 的数组,这个数组的下标为从 \(1\) 到 \(n\) 的正整数。

一共有 \(m\) 个操作,可以分为两种:

  • 0 l r 表示将第 \(l\) 个到第 \(r\) 个数( \(a_l,a_{l+1} ...a_r\))中的每一个数 \(a_i\) 替换为 \(c^{a_i}\),即 \(c\) 的 \(a_i\) 次方,其中 \(c\) 是输入的一个常数,也就是执行赋值 \(a_i = c^{a_i}\)。

  • 1 l r 求第 \(l\) 个到第 \(r\) 个数的和,也就是输出: \(\sum_{i=l}^{r}a_i\)

因为这个结果可能会很大,所以你只需要输出结果 \(\bmod \space p\) 的值即可。

输入格式

第一行有四个整数 \(n, m, p, c\),所有整数含义见问题描述。
接下来一行 \(n\) 个整数,表示 \(a\) 数组的初始值。
接下来 \(m\) 行,每行三个整数,其中第一个整数表示了操作的类型。

  • 如果是 \(0\) 的话,表示这是一个修改操作,操作的参数为 \(l, r\)。
  • 如果是 \(1\) 的话,表示这是一个询问操作,操作的参数为 \(l, r\)。

输出格式

对于每个询问操作,输出一行,包括一个整数表示答案 \(\bmod \space p\) 的值。

样例 #1

样例输入 #1

4 4 7 2
1 2 3 4
0 1 4
1 2 4
0 1 4
1 1 3

样例输出 #1

0
3

样例 #2

样例输入 #2

1 40 19910626 2
0
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1

样例输出 #2

1
2
4
16
65536
11418102
18325590
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558

提示

【数据范围】

对于 \(0\%\) 的测试点,和样例一模一样;

对于另外 \(10\%\) 的测试点,没有修改;

对于另外 \(20\%\) 的测试点,每次修改操作只会修改一个位置(也就是 \(l = r\) ),并且每个位置至多被修改一次;

• 对于另外 \(10\%\) 的测试点, \(p = 2\);

对于另外 \(10\%\) 的测试点, \(p = 3\);

对于另外 \(10\%\) 的测试点, \(p = 4\);

对于另外 \(20\%\) 的测试点, \(1\le n,m \le 100\);

对于 \(100\%\) 的测试点, \(1\le n,m \le 5\times 10^4\),\(1 \le p \le 10^8\),\(0< c < p\),\(0 \le a_i < p\)。

Solution:

为了方便,我们将 形如 \(c^{c^c}\) 的东西当作 \(c^{(c^c)}\) 。

这个操作看上去就十分神仙,所以我们考虑使用 Segment beats 均摊方法。

受到第二个样例的启发,我们猜想可能某个数操作到一定地步后便不会再动了。

我们考虑拓展欧拉定理

其叙述是若 \(b\ge\varphi(p)\),则有 \(a^b\equiv a^{b\,\bmod\,\varphi(p)+\varphi(p)}\pmod p\)

我们现在想象一个无限高的幂塔,即:

\(c^{c^{c^{c^{...}}}}\bmod p\)

那么第一层的 \(c\) 需要 \(\bmod p\),第二层的 \(c\) 便需要 \(\bmod \varphi(p)\),第三层的 \(c\) 则需要 \(\bmod\varphi(\varphi(p))\) ......

什么时候像样例二一样终止?

我们发现若我们设定一个变量 \(x=p\),不断地令 \(x=\varphi(x)\) 的话,那么 \(x\) 将在 \(O(\log p)\) 次后降为 \(1\)。

如何证明?

由 \(\varphi\) 的计算式 \(\varphi(x)=\prod(p-1)p^{k-1}\) 和 \(\varphi(x)=x\prod\frac{p-1}{p}\) 可以得到两个结论。

\(1.\) 若 \(x\) 为奇数,则 \(\varphi(x)\) 为偶数。

​ 证明的话,由于它是奇数,所以他的所有质因子 \(p\) 都是奇数,故而所有 \((p-1)p^{k-1}\) 都是偶数,它们之积也自然是偶数了。

\(2.\) 若 \(x\) 为偶数,则 \(\varphi(x)\leq\frac{x}{2}\)。

​ 证明的话,由于偶数,所以有一个质因子 \(p\),所以 \(x\) 至少乘了一个 \(\frac{1}{2}\) 的系数。

综上可知,\(x\) 每迭代两次便会下降一半,由此,\(x\) 将在 \(O(\log p)\) 次后降为 \(1\) 的结论得到证明。

然后考虑变成 \(1\) 之后有什么用。

举一个例子。

\(c^{c^{c^{a_i}}}\) 和 \(c^{c^{a_i}}\) 有很大的不同吧 \((a_i,c\ne0)\)。

但是如果到了第三层模数已经变为 \(1\) 了呢?

那么第三层的 \(c^{a_i}\) 和 \(a_i\) 就本质上无区别,因为它们都 \(\ge1\) 且 \(\bmod 1=0\)。

所以说,如果 \(\varphi(\varphi(p))=1\,(\)第三层模数为 \(1)\),我们就会有:

\(c^{c^{c^{a_i}}}\equiv c^{c^{a_i}}\pmod p\)

同理 ,\(c\) 更多的时候都是相等的。

所以我们得到了一个重要的结论,每个位置上的数在进行 \(O(\log p)\) 次操作后继续操作不会改变。

套用 Segment beats 均摊方法即可。

实现起来会稍微有一点麻烦,麻烦的主要来源是拓展欧拉定理的适用条件 \(b\ge\varphi(p)\) ,因此我们每取一次模还需要判定该数与模数的大小关系以决定该数是否要 \(+\varphi(p)\),虽然麻烦但并不难,读者可自行考虑实现。

然后你每一次求 \(c^{c^{c^{a_i}}}(k 个 c)\) 的话使用朴素方法是 \(O(k\log v)\) 的 \((v\) 为值域\()\),因为每层都要做一遍快速幂,由于 \(k_{\operatorname{max}}=O(\log p)\),而每个数又都要操作 \(O(\log p)\) 次才能最终保持不动,所以总复杂度是 \(O(n\log^2 p\log v)\) 难以通过。

考虑省掉快速幂的一个 \(\log\)。

观察到我们每次要求形如 \(c^b\bmod k\) 的式子。

而底数 \(c\) 固定,\(k\) 至多只有 \(O(\log p)\) 个,那么可以使用光速幂对于每一个模数都 \(O(\sqrt v)\) 预处理,每次 \(O(1)\) 查询,总复杂度 \(O(\sqrt v\log p+n\log p\log v)\) ,可以通过本题。

#include<bits/stdc++.h>
using namespace std;
#define inf 0x7fffffff
#define timeused() (double)clock()/CLOCKS_PER_SEC
#define rep(i,a,b) for(register int i=a,i##end=b;i<=i##end;++i)
#define repp(i,a,b) for(register int i=a,i##end=b;i>=i##end;--i)
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
template<typename T> inline T rd(T& x){
    T f=1;x=0;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(T)(c-'0');
    x*=f;
    return x;
}
ll ls(ll x){return x<<1;}
ll rs(ll x){return x<<1|1;}
ll n,m,c,a[50005],p[50005],tot,mi[50005][55],yz,B[55][10005],G[55][10005],poww[55],tmp[55];
struct node{
    ll now,sum;
    bool ok;
    void clear(){ok=now=sum=0;}
}b[200005];
node merge(node x,node y){
    node z;
    z.ok=(x.ok&&y.ok);
    z.sum=(x.sum+y.sum)%p[0];
    return z;
}
void maintain(ll x){b[x]=merge(b[ls(x)],b[rs(x)]);}
ll phi(ll x){
    ll ans=x;
    rep(i,2,sqrt(x)){
        if(x%i==0){
            ans/=i;
            ans*=i-1;
        }
        while(x%i==0) x/=i;
    }
    if(x>1){
        ans/=x;
        ans*=x-1;
    }
    return ans;
}
void build(ll x,ll l,ll r){
    if(l==r){
        b[x].clear();
        b[x].sum=mi[l][0];
        b[x].ok=b[x].now>=tot;
        return;
    }
    ll mid=l+r>>1;
    build(ls(x),l,mid);
    build(rs(x),mid+1,r);
    maintain(x);
}
void upd(ll x,ll l,ll r,ll L,ll R){
    if(b[x].ok) return;
    if(l==r){
        ++b[x].now;
        b[x].sum=mi[l][b[x].now];
        b[x].ok=b[x].now>=tot;
        return;
    }
    ll mid=l+r>>1;
    if(L<=mid) upd(ls(x),l,mid,L,R);
    if(R>mid) upd(rs(x),mid+1,r,L,R);
    maintain(x);
}
ll query(ll x,ll l,ll r,ll L,ll R){
    if(L<=l&&R>=r) return b[x].sum%p[0];
    ll ans=0,mid=l+r>>1;
    if(L<=mid) ans=(ans+query(ls(x),l,mid,L,R))%p[0];
    if(R>mid) ans=(ans+query(rs(x),mid+1,r,L,R))%p[0];
    return ans%p[0];
}
int main(){
    rd(n);
    rd(m);
    rd(p[0]);
    yz=10000;
    rd(c);
    poww[0]=1;
    rep(i,1,35){
        poww[i]=poww[i-1]*c;
        if(poww[i]>=inf) poww[i]=inf;
    } 
    while(p[tot]-1){
        ++tot;
        p[tot]=phi(p[tot-1]);
    }
    p[++tot]=1;
    p[++tot]=1;
    p[++tot]=1;
    rep(i,0,tot){
        B[i][0]=G[i][0]=1;
        rep(j,1,yz) B[i][j]=B[i][j-1]*c%p[i];
        G[i][1]=B[i][yz];
        rep(j,2,yz) G[i][j]=G[i][j-1]*B[i][yz]%p[i];
    }
    rep(i,1,n){
        rd(a[i]);
        tmp[0]=a[i];
        rep(j,1,tot){
            if(tmp[j-1]>50) tmp[j]=inf;
            else tmp[j]=poww[tmp[j-1]];
        }
        rep(j,0,tot){
            if(c==1){
                mi[i][j]=1;
                if(!j) mi[i][j]=a[i];
                continue;
            }
            mi[i][j]=a[i]%p[j];
            if(a[i]>=p[j]) mi[i][j]+=p[j];
            repp(k,j-1,0){
                mi[i][j]=B[k][mi[i][j]%yz]*G[k][mi[i][j]/yz]%p[k];
                if(tmp[j-k]>=p[k]&&k) mi[i][j]+=p[k];
            }
        }
    }
    build(1,1,n);
    while(m--){
        ll opt,l,r;
        rd(opt);
        rd(l);
        rd(r);
        if(!opt) upd(1,1,n,l,r);
        else printf("%lld\n",query(1,1,n,l,r));
    }
}

标签:六省,log,13700558,ll,mi,varphi,tot,P3747,联考
来源: https://www.cnblogs.com/Miracle-blog/p/16340385.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有