题目背景

大样例下发链接: https://pan.baidu.com/s/1nuVpRS1 密码: sfxg

注意:本题大样例4的输出文件修改为 https://pan.baidu.com/s/1bUWuZW

奈芙莲·卢可·印萨尼亚(Nephren-Ruq-Insania)

noip模拟赛 Nephren Ruq Insania

同为妖精仓库的成体妖精兵,天赋不如珂朵莉一般,只是一个平凡的妖精.

睡觉时如同毯子一般在威廉身上为其保暖。习惯于粘着威廉,在梦境中与艾尔梅莉亚交谈时,自称就像是威廉的宠物一样。

noip模拟赛 Nephren Ruq Insania

本题题面中含有大量的剧透,建议做题之前将这部番剧看完(

题目描述

她只是一个非常普通的黄金妖精。

在援救打捞队的作战中,他们不幸与(几乎是所有的)第六兽相遇了。

此时的珂朵莉因为接触到星神艾露可本体,正处于昏迷之中。而威廉也无法离开珂朵莉。

noip模拟赛 Nephren Ruq Insania

默默守护在房间外的她,提起圣剑,走向了战场。

noip模拟赛 Nephren Ruq Insania

作为本身天赋只是一般的妖精少女,她难以对抗无数倍于自己的六号兽。

没有多久,她开始体力不支。

终于,在源源不断的六号兽面前,她难以抵挡了……

noip模拟赛 Nephren Ruq Insania

终于,由于魔力过度激发,她已经处在了魔力失控的边缘……

”威廉,拯救,是我们黄金妖精的使命。“

”况且,威廉之前已经救过我们了。“

”所以,已经没有问题了。“

noip模拟赛 Nephren Ruq Insania

威廉想要救下奈芙莲,但是他自己也已经处于崩溃的边缘。

冥冥之中他想起了曾经学习过的一种魔法。在这最后一刻,或许已经是唯一的办法了。

这种魔法操作的对象是一个咒语组成的序列,每一个单独的咒语拥有自己的法力值。

威廉需要不断地按照之前的记忆,对某一段区间的法力值加上一个数,或者求出某一段区间的法咒共鸣。

noip模拟赛 Nephren Ruq Insania

noip模拟赛 Nephren Ruq Insania

noip模拟赛 Nephren Ruq Insania

noip模拟赛 Nephren Ruq Insania

分析:这道题部分分还是比较多的.第一个数据点看起来数据非常小,但是3^3^3^3^3mod p会算不出来,因为次数很大,不能直接对次数取模.怎么将次数变小呢?欧拉定理! noip模拟赛 Nephren Ruq Insania,可以发现如果这道题就是不断地使用欧拉定理,直到φ(p)变成1或者计算完整个区间,这实际上就是一个递归的过程.用线段树进行区间修改,单点查询。

      有几个地方需要注意:

      1.如果区间[l,r]中第x位是1,那么[x,r]都不需要考虑了,因为1^n = 1.

      2.欧拉定理成立的条件是x >= φ(p),而由于忽略0和1的情况,2^2^2^2^2就足以满足数据范围了,所以暴力枚举5位乘起来看看是不是>=φ(p)就可以了.如果<φ(p)就可以直接算,而不需要欧拉定理了.

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 500010;

int n, m, prime[20000010], phi[20000010], cnt, flag[maxn];
long long tag[maxn << 2], c[maxn << 2], a[maxn], L[maxn << 2], R[maxn << 2];
bool vis[20000010];

void init()
{
    phi[1] = 1;
    for (int i = 2; i <= 20000000; i++)
    {
        if (!vis[i])
        {
            prime[++cnt] = i;
            phi[i] = i - 1;
        }
        for (int j = 1; j <= cnt; j++)
        {
            int t = i * prime[j];
            if (t > 20000000)
                break;
            vis[t] = 1;
            if (i % prime[j] == 0)
            {
                phi[t] = phi[i] * prime[j];
                break;
            }
            phi[t] = phi[i] * (prime[j] - 1);
        }
    }
}

void pushup(int o)
{
    c[o] = c[o * 2] + c[o * 2 + 1];
}

void pushdown(int o)
{
    if (tag[o])
    {
        tag[o * 2] += tag[o];
        tag[o * 2 + 1] += tag[o];
        c[o * 2] += (R[o * 2] - L[o * 2] + 1) * tag[o];
        c[o * 2 + 1] += (R[o * 2 + 1] - L[o * 2 + 1] + 1) * tag[o];
    }
    tag[o] = 0;
}

void build(int o, int l, int r)
{
    L[o] = l;
    R[o] = r;
    if (l == r)
    {
        c[o] = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(o * 2, l, mid);
    build(o * 2 + 1, mid + 1, r);
    pushup(o);
}

void update(int o, int l, int r, int x, int y, int v)
{
    if (x <= l && r <= y)
    {
        tag[o] += v;
        c[o] += v;
        return;
    }
    pushdown(o);
    int mid = (l + r) >> 1;
    if (x <= mid)
        update(o * 2, l, mid, x, y, v);
    if (y > mid)
        update(o * 2 + 1, mid + 1, r, x, y, v);
    pushup(o);
}

long long query(int o, int l, int r, int pos)
{
    if (l == r)
        return c[o];
    pushdown(o);
    int mid = (l + r) >> 1;
    if (pos <= mid)
        return query(o * 2, l, mid, pos);
    else
        return query(o * 2 + 1, mid + 1, r, pos);
}

long long Cal(int q)
{
    if (flag[q] == m)
        return a[q];
    flag[q] = m;
    return a[q] = query(1, 1, n, q);
}

long long qpow(long long a, long long b, long long mod)
{
    a %= mod;
    long long res = 1;
    while (b)
    {
        if (b & 1)
            res = (res * a) % mod;
        a = (a * a) % mod;
        b >>= 1;
    }
    return res;
}

long long jisuan(int l, int r, int mod)
{
    if (mod == 1)
        return 1;
    if (l == r)
    {
        long long t = Cal(l);
        if (t < mod)  //直接算
            return t % mod;
        else
            return (t % mod) + mod;
    }
    int minn = min(n, l + 5);
    for (int i = l + 1; i <= minn; i++)
        if (Cal(i) == 1)
        {
            minn = i;
            break;
        }
    long long p = Cal(minn), tot = 0;
    for (int i = minn - 1; i >= l + 1; i--)
    {
        tot = p;
        p = 1;
        while (tot--)
        {
            p *= Cal(i);
            if (p >= phi[mod])
                return qpow(Cal(l) % mod, jisuan(l + 1, r, phi[mod]) + phi[mod], mod);
        }
    }
    return qpow(Cal(l) % mod, jisuan(l + 1, r, phi[mod]), mod);
}

int main()
{
    memset(flag, -1, sizeof(flag));
    init();
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    build(1, 1, n);
    while (m--)
    {
        int op, l, r, mod;
        scanf("%d%d%d%d", &op, &l, &r, &mod);
        if (op == 1)
            update(1, 1, n, l, r, mod);
        else
            printf("%lld\n", jisuan(l, r, mod) % mod);
    }

    return 0;
}

 

相关文章: