noip模擬賽 Nephren Ruq Insania


題目背景

大樣例下發鏈接: https://pan.baidu.com/s/1nuVpRS1 密碼: sfxg

注意:本題大樣例4的輸出文件修改為 https://pan.baidu.com/s/1bUWuZW

奈芙蓮·盧可·印薩尼亞(Nephren-Ruq-Insania)

同為妖精倉庫的成體妖精兵,天賦不如珂朵莉一般,只是一個平凡的妖精.

睡覺時如同毯子一般在威廉身上為其保暖。習慣於粘着威廉,在夢境中與艾爾梅莉亞交談時,自稱就像是威廉的寵物一樣。

本題題面中含有大量的劇透,建議做題之前將這部番劇看完(

題目描述

她只是一個非常普通的黃金妖精。

在援救打撈隊的作戰中,他們不幸與(幾乎是所有的)第六獸相遇了。

此時的珂朵莉因為接觸到星神艾露可本體,正處於昏迷之中。而威廉也無法離開珂朵莉。

默默守護在房間外的她,提起聖劍,走向了戰場。

作為本身天賦只是一般的妖精少女,她難以對抗無數倍於自己的六號獸。

沒有多久,她開始體力不支。

終於,在源源不斷的六號獸面前,她難以抵擋了……

終於,由於魔力過度激發,她已經處在了魔力失控的邊緣……

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

”況且,威廉之前已經救過我們了。“

”所以,已經沒有問題了。“

威廉想要救下奈芙蓮,但是他自己也已經處於崩潰的邊緣。

冥冥之中他想起了曾經學習過的一種魔法。在這最后一刻,或許已經是唯一的辦法了。

這種魔法操作的對象是一個咒語組成的序列,每一個單獨的咒語擁有自己的法力值。

威廉需要不斷地按照之前的記憶,對某一段區間的法力值加上一個數,或者求出某一段區間的法咒共鳴。

分析:這道題部分分還是比較多的.第一個數據點看起來數據非常小,但是3^3^3^3^3mod p會算不出來,因為次數很大,不能直接對次數取模.怎么將次數變小呢?歐拉定理! ,可以發現如果這道題就是不斷地使用歐拉定理,直到φ(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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM