zoukankan      html  css  js  c++  java
  • 洛谷 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

  • 相关阅读:
    SourceForge上发布dedup util 收藏
    IBM快速整合Diligent 触动了谁的神经?
    Data Domain揭开其神秘面纱 加速中国业务发展
    Java NIO原理和使用
    用PDB库调试Python程序
    windows下配置eclipse + Python + PyDev + tornado,并使用pylint进行静态检测
    函数fork与vfork的区别与联系详解
    关于C++中友元类和友元函数的示例讲解
    const成员函数
    pthread_cond_wait()深入解析
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9767993.html
Copyright © 2011-2022 走看看