P3934 [Ynoi2016] 炸脖龙 I Solution

Description

给定序列 a = ( a 1 , a 2 , ⋯   , a n ) a=(a_1,a_2,\cdots,a_n) a=(a1,a2,,an).

m m m 个操作,分以下两种:

  1. modify ⁡ ( l , r , k ) \operatorname{modify}(l,r,k) modify(l,r,k):对每个 i ∈ [ l , r ] i \in [l,r] i[l,r] 执行 a i ← a i + k a_i \leftarrow a_i+k aiai+k
  2. query ⁡ ( l , r , p ) \operatorname{query}(l,r,p) query(l,r,p):定义 f ( l , l ) = a l f(l,l)=a_l f(l,l)=al f ( l , r ) = a l f ( l + 1 , r )    ( l < r ) f(l,r)=a_l^{f(l+1,r)} \;(l < r) f(l,r)=alf(l+1,r)(l<r),求 f ( l , r )   m o d   p f(l,r) \bmod p f(l,r)modp

Limitations

1 ≤ n , m ≤ 5 × 1 0 5 1 \le n,m \le 5\times 10^5 1n,m5×105
1 ≤ a i ≤ 2 × 1 0 9 1 \le a_i \le 2\times 10^9 1ai2×109
1 ≤ p ≤ 2 × 1 0 7 1 \le p \le 2\times 10^7 1p2×107
0 ≤ k ≤ 2 × 1 0 9 0 \le k \le 2\times 10^9 0k2×109
2.5 s , 512 MB 2.5\text{s},512\text{MB} 2.5s,512MB

Solution

连幂运算不满足结合律,不能线段树维护。
考虑扩展欧拉定理
a b ≡ a b   m o d   ϕ ( p ) + ϕ ( p ) × [ b ≥ ϕ ( p ) ] ( m o d p ) a^b \equiv a^{b \bmod \phi(p)+\phi(p)\times[b \ge \phi(p)]} \pmod p ababmodϕ(p)+ϕ(p)×[bϕ(p)](modp)
我们直接暴力 dfs 遍历每个数求值,由于每个 p p p 最多递归 log ⁡ p \log p logp 层,因此不会超时。
但是,如何判断 [ b ≥ ϕ ( p ) ] [b \ge \phi(p)] [bϕ(p)]?其实不难,跑快速幂时判断一下即可。
然后考虑边界情况:

  1. p = 1 p=1 p=1 时,答案一定为 0 0 0
  2. a l = 1 a_l=1 al=1 时,答案一定为 1 1 1

a a a 用树状数组维护,再筛一下 ϕ ( p ) \phi(p) ϕ(p) 即可。

Code

3.58 KB , 3.1 s , 95.71 MB    (in   total,   C++   20   with   O2)   3.58\text{KB},3.1\text{s},95.71\text{MB}\;\texttt{(in total, C++ 20 with O2) } 3.58KB,3.1s,95.71MB(in total, C++ 20 with O2) 

// Problem: P3934 [Ynoi2016] 炸脖龙 I
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3934
// Memory Limit: 512 MB
// Time Limit: 2500 ms
// 
// Powered by CP Editor (https://cpeditor.org)

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

using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;

template<class T>
bool chmax(T &a, const T &b){
	if(a < b){ a = b; return true; }
	return false;
}

template<class T>
bool chmin(T &a, const T &b){
	if(a > b){ a = b; return true; }
	return false;
}

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

template<class T>
struct fenwick{
	int n;
	vector<T> c;
	
	fenwick() {}
	fenwick(int _n): n(_n){
		c.resize(n + 1);
	}
	
	fenwick(const vector<T> &a): n(a.size()){
		c.resize(n + 1);
		for(int i = 1; i <= n; i++){
			c[i] = c[i] + a[i - 1];
			int j = i + lowbit(i);
			if(j <= n) c[j] = c[j] + c[i];
		}
	}
	
	void add(int x, const T& v){
		for(int i = x + 1; i <= n; i += lowbit(i)) c[i] = c[i] + v;
	}
	
	T ask(int x){
		T ans{};
		for(int i = x + 1; i; i -= lowbit(i)) ans = ans + c[i];
		return ans;
	}
	
	T ask(int l, int r){
		return ask(r) - ask(l - 1);
	}
};

using Node = pair<i64, bool>;

Node power(i64 a, i64 b, i64 p) {
    Node res(1, false);
    
    i64 t = a % p;
    if (a >= p) {
        res.second = true;
        res.first %= p;
    }
    
    while (b) {
        if (b & 1) {
            res.first *= t;
        }
        if (res.first >= p) {
            res.second = true;
            res.first %= p;
        }
        
        t *= t;
        if ((b / 2) && t >= p) {
            res.second = true;
            t %= p;
        }
        b >>= 1;
    }
    return res;
}

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	
	int n, m;
	scanf("%d %d", &n, &m);
	
	vector<i64> a(n);
	fenwick<i64> bit(n);
	for (int i = 0; i < n; i++) {
	    scanf("%lld", &a[i]);
	    bit.add(i, a[i] - (i > 0 ? a[i - 1] : 0LL));
	}
	
	vector<bool> np;
	vector<int> pri, phi;
	auto sieve = [&](int n) {
	    np.resize(n + 1, false);
	    phi.resize(n + 1, 0);
	    
	    phi[1] = 1;
	    for (int i = 2; i <= n; i++) {
	        if (!np[i]) {
	            pri.push_back(i);
	            phi[i] = i - 1;
	        }
	        
	        for (int j = 0; j < pri.size() && 1LL * i * pri[j] <= n; j++) {
	            np[i * pri[j]] = true;
	            if (i % pri[j] == 0) {
	                phi[i * pri[j]] = phi[i] * pri[j];
	                break;
	            }
	            phi[i * pri[j]] = phi[i] * (pri[j] - 1);
	        }

	    }
	};
	sieve(2e7);
	
	auto solve = [&](auto &&self, int l, int r, i64 p) -> Node {
        i64 t = bit.ask(l);
        if (p == 1) {
            return Node(0, true);
        }
        if (l == r) {
            return Node(t % p, t >= p);
        }
        if (t == 1) {
            return Node(1, false);
        }
        
        Node mid = self(self, l + 1, r, phi[p]);
        if (mid.second) {
            mid.first += phi[p];
        }
        return power(t, mid.first, p);
    };
    
    for (int i = 0; i < m; i++) {
        int op, l, r;
        i64 p;
        scanf("%d %d %d %lld", &op, &l, &r, &p);
        l--, r--;
        
        if (op == 1) {
            bit.add(l, p);
            bit.add(r + 1, -p);
        }
        else {
            i64 res = solve(solve, l, r, p).first;
            printf("%lld\n", (res % p + p) % p);
        }
    }
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值