洛谷 P3747 [六省联考2017]相逢是问候 解题报告

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

题目描述

( ext {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)

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

输入输出格式

输入格式:

第一行有四个整数 (n), (m), (p), (c),所有整数含义见问题描述。

接下来一行 (n) 个整数,表示 (a) 数组的初始值。

接下来 (m) 行,每行三个整数,其中第一个整数表示了操作的类型。

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

输出格式:

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

说明

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

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

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

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

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

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

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

  • 对于 (100\%) 的测试点, (1 le n le 50000 ; 1 le m le 50000 ; 1 le p le 100000000; 0 < c <p; 0 ≤ a_i < p)


好坑啊,写到自闭了。。

有结论
(c^{c^{{c..}^a}}mod p)

递归的规模是(log_2p)

证明用一下扩展欧拉定理就行了

等价于(p,varphi(p),varphi(varphi(p))...)有多少层。

对于(p)是偶数,至少减少一半

对于(p)是奇数,下一次一定是偶数


于是对每个位置,我们每次直接操作,暴力求改的值。

拿一颗平衡树维护还没有够次数的位置,拿树状数组维护。

修改操作的上界是(O(nlogp))


考虑每次暴力求改的值,发现复杂度是(O(log^2p))

三个(log)应该比较难卡过去

扩展欧拉定理的层数不好优化,想办法优化快速幂

发现底数都是(c),可以分块预处理

对每个模数(p)预处理(c^1)~(c^{10000}),然后对(t=c^{10000})再预处理一下(t^1)~(t^{10000})

每次可以(O(1))的把两块合并在一起


如果你一直wa3和wa20

可以试试这个数据

1 6 4 2
0
0 1 1 
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1

这里要注意扩展欧拉定理

(a^t equiv a^{min(t,t mod varphi(p) + varphi(p))} (mod p))

后面什么时候要加(varphi(p)),什么时候不加


Code:

#include <cstdio>
#include <set>
#define ll long long
const int N=5e4+10;
int n,m,cnt[N];
ll p,c,las[N],a[N];
std::set <int> s;
std::set <int>::iterator it;
ll quickpow(ll d,ll k,ll mod)
{
    ll f=1;int flag=0;
    if(f>=mod) flag=1;
    f%=mod;
    while(k)
    {
        if(k&1)
        {
            if(f*d>=mod) flag=1;
            f=f*d%mod;
        }
        if(d*d>=mod) flag=1;
        d=d*d%mod;
        k>>=1;
    }
    return flag?f+mod:f;
}
ll phi(ll ba)
{
    ll ans=ba;
    for(ll i=2;i*i<=ba;i++)
    {
        if(ba%i==0)
        {
            ans=ans*(i-1)/i;
            while(ba%i==0) ba/=i;
        }
    }
    if(ba!=1) ans=ans*(ba-1)/ba;
    return ans;
}
ll Mod[100],mxd;
void get(ll mod)
{
    if(mod==1)
    {
        Mod[++mxd]=mod;
        Mod[++mxd]=mod;
        return;
    }
    Mod[++mxd]=mod;
    get(phi(mod));
}
const int M=10000;
ll S[100][M+10],T[100][M+10];
void initpow()
{
    for(int i=1;i<=mxd;i++)
    {
        for(int j=0;j<=M;j++)
            S[i][j]=quickpow(c,j,Mod[i]);
        ll t=quickpow(c,M,Mod[i])%Mod[i];
        for(int j=1;j<=M;j++)
            T[i][j]=quickpow(t,j,Mod[i])%Mod[i]+Mod[i];
    }
}
int De;
ll Pow(ll d,int de)
{
    return T[de][d/M]?(T[de][d/M]*S[de][d%M])%Mod[de]+Mod[de]:S[de][d%M];
}
ll dfs(ll ba,int de,int dep,ll mod)
{
    if(dep==0) return ba>=mod?ba%mod+mod:ba;
    return Pow(dfs(ba,de+1,dep-1,Mod[de+1]),de);
}
ll t[N];
void change(int pos,ll d)
{
    while(pos<=n) t[pos]+=d,pos+=pos&-pos;
}
ll query(int pos)
{
    ll sum=0;
    while(pos) sum+=t[pos],pos-=pos&-pos;
    return sum;
}
int main()
{
    scanf("%d%d%lld%lld",&n,&m,&p,&c);
    for(int i=1;i<=n;i++)
        scanf("%lld",a+i),change(i,las[i]=a[i]),s.insert(i);
    get(p);
    initpow();
    for(int op,l,r,i=1;i<=m;i++)
    {
        scanf("%d%d%d",&op,&l,&r);
        if(op==0)
        {
            it=s.lower_bound(l);
            while(it!=s.end()&&*it<=r)
            {
                int pos=*it;
                De=++cnt[pos];
                ll d=dfs(a[pos],1,De,p);
                change(pos,d-las[pos]);
                las[pos]=d;
                it++;
                if(cnt[pos]==mxd-1) s.erase(pos);
            }
        }
        else
            printf("%lld
",(query(r)-query(l-1))%p);
    }
    return 0;
}

2018.10.10

原文地址:https://www.cnblogs.com/butterflydew/p/9767993.html