[Ynoi2016]炸脖龙I/Nephren Ruq Insania

本文解析了一道罕见的Ynoi奈芙莲题目,介绍了使用拓展欧拉定理解决暴力算法问题的思路。通过分析ϕ(p)phi(p)ϕ(p)的性质,提出了一种基于树状数组维护差分的解决方案,详细阐述了快速幂运算的实现,并给出了代码示例。

Ynoi竟然出了个奈芙莲的题,少见啊

Ynoi竟然有个不卡常的题,更少见了


这道题其实思路非常好想,本质上就是一个暴力,但是要用到拓展欧拉定理,是什么呢?

a c ≡ { a c , c < ϕ ( p ) a c   m o d   ϕ ( p ) + ϕ ( p ) , c ≥ ϕ ( p )   m o d   p a^c\equiv\begin{cases}a^c,c<\phi(p) \\ a^{c\bmod \phi(p)+\phi(p)},c\geq\phi(p)\end{cases} \bmod p ac{ac,c<ϕ(p)acmodϕ(p)+ϕ(p),cϕ(p)modp

这个东西有什么用呢?做过这道题的就应该很明显了

我们观察 ϕ ( p ) \phi(p) ϕ(p)一定 ≤ n 2 \leq\frac{n}{2} 2n,那么也就是说最多经过 log ⁡ p \log p logp次之后,我们的 ϕ ( ϕ ( ϕ ( . . . ϕ ( p ) ) ) ) = 1 \phi(\phi(\phi(...\phi(p))))=1 ϕ(ϕ(ϕ(...ϕ(p))))=1,这个时候根据我们上面的拓展欧拉定理,我们就不需要继续算剩下的部分了,因为剩下的部分算完肯定是 1 1 1

也就是说我们对于每次查询,从 x x x暴力往右扫,每次都让 p = ϕ ( p ) p=\phi(p) p=ϕ(p),那么经过一定次数之后剩下的就不用管了,然后我们再回溯更新这一部分的答案就可以

因为有区间加之类的操作,所以我们用树状数组维护差分,就可以求出每一个位置上的数是多少了

其实这题根这道题也挺像的吧,但是上帝那道题的数据比较水,我们会发现,当我们的 c < ϕ ( p ) c<\phi(p) c<ϕ(p)的时候,我们是不能 + ϕ ( p ) +\phi(p) +ϕ(p)的,这个东西就非常的恶心,我们需要特判一下

特判的方法也比较简单,我们在做快速幂的过程中,每次计算完先不取模,如果发现比 p p p大, f l a g = 1 flag=1 flag=1,然后再取模,做完快速幂之后再判断如果 f l a g = 1 flag=1 flag=1,那么再加上 ϕ ( p ) \phi(p) ϕ(p)

快速幂大概是这个样子的

int Qpow(int base,int ind,int mod){
    int res=1;
    flag=false;
    if(base>=mod)flag=true,base%=mod;
    while(ind){
        if(ind&1){
            res=res*base;
            if(res>=mod)flag=true,res%=mod;
        }
        base=base*base;
        if(base>=mod)flag=true,base%=mod;
        ind>>=1;
    }
    return res;
}

好长啊

查询的时候其实是不用写 d f s dfs dfs的,我们可以直接手动模拟栈,先把要求的部分的模数都预处理出来,然后从右往左算就可以

        else{
            int now=x;
            modn[x]=p;
            p=phi[p];
            while(p>1&&now<y){
                modn[++now]=p;
                p=phi[p];
            }
            int res=1;
            _Rep(i,now,x){
                res=Qpow(ask(i),res,modn[i]);
                if(flag)res+=modn[i];
            }
            printf("%lld\n",res%modn[x]);
        }

由于 p ≤ 2 × 1 0 7 p\leq 2\times10^7 p2×107,所以我们要线性筛,然后这题空间500MB,放心的开longlong吧。

其他细节没什么了,只要不像我一样线性筛出一堆锅就好


然后是这题的复杂度,我们发现,每次询问我们最多查询 log ⁡ p \log p logp次,每次需要 log ⁡ n \log n logn的时间,然后算快速幂需要 log ⁡ p \log p logp次的时间,所以这题的总复杂度应该是 O ( m log ⁡ n log ⁡ 2 p ) O(m\log n\log^2 p) O(mlognlog2p)

毒瘤的lxl这题仁慈的开了3s时限

代码:

#include <bits/stdc++.h>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;

const int N=5e5+5;
const int M=2e7+5;

template<typename T> void read(T &x){
   x=0;int f=1;
   char c=getchar();
   for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
   for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

# define int long long

int n,m;
int a[N],bit[N];
int phi[M],prime[N*10],tot;
int modn[N];
bool isp[M],flag;

int lowbit(int o){
    return o&-o;
}

void add(int o,int x){
    for(;o<=n;o+=lowbit(o))bit[o]+=x;
}

int ask(int o){
    int res=0;
    for(;o;o-=lowbit(o))res+=bit[o];
    return res;
}

void init()
{
    phi[1]=1;
    for(int i=2;i<=2e7;i++){
        if(isp[i])prime[++tot]=i,phi[i]=i-1;
        for(int j=1;j<=tot&&i*prime[j]<=2e7;j++){
            isp[i*prime[j]]=false;
            if(i%prime[j]==0){
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            else phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
}

int Qpow(int base,int ind,int mod){
    int res=1;
    flag=false;
    if(base>=mod)flag=true,base%=mod;
    while(ind){
        if(ind&1){
            res=res*base;
            if(res>=mod)flag=true,res%=mod;
        }
        base=base*base;
        if(base>=mod)flag=true,base%=mod;
        ind>>=1;
    }
    return res;
}

signed main()
{
    memset(isp,true,sizeof(isp));
    read(n),read(m);
    Rep(i,1,n)read(a[i]);
    Rep(i,1,n)add(i,a[i]-a[i-1]);
    init();
    Rep(i,1,m){
        int opt,x,y,p;
        read(opt),read(x),read(y),read(p);
        if(opt==1){
            add(x,p);
            add(y+1,-p);
        }
        else{
            int now=x;
            modn[x]=p;
            p=phi[p];
            while(p>1&&now<y){
                modn[++now]=p;
                p=phi[p];
            }
            int res=1;
            _Rep(i,now,x){
                res=Qpow(ask(i),res,modn[i]);
                if(flag)res+=modn[i];
            }
            printf("%lld\n",res%modn[x]);
        }
    }
    return 0;
}

因为这题是Ynoi,所以来说点没用的

奈芙莲其实戏份挺少的,因为第四卷没有拍嘛

虽然她没有爱尔和珂朵莉的美貌

但是她达成了一件珂朵莉都没有达成的事,抱着威廉睡觉

而且,她是不是也算是在最后一刻绽放呢?

她难道不也是最幸福的女孩子吗?

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值