• [六省联考2017]相逢是问候(扩展欧拉定理+预处理幂)


    https://www.luogu.com.cn/problem/P3747

    已经记不请上一次遇到扩展欧拉定理是什么时候了。

    (a^b~mod~p=)
    (b<phi(p),a^b~mod~p)
    (bge phi(p),a^{b~mod~phi(p)+phi(p)}~mod~p)

    假设模数一直取(phi)的序列为(p[1],p[2],…,p[p0](p0 le 2log_2(mo)))

    对于这题,可以对每个数记录一个(cnt)表示已经pow了多少次,当(cnt>p0)后,都和(cnt=p0+1)时的值一样

    注意是和(cnt=p0+1)时的值一样,为了方便,多开一位:p[++p0]=1

    用线段树维护区间(cnt)最小值,如果(le p0),就下去修改就好了。

    每个数要需要修改(log)次,每次修改要(log^2)的时间求新的答案(一个log来自快速幂),这样会T两个点。

    注意到底数都是(c),所以预处理(c^{0..15000})(c^{0..15000*15000})(mod)每个(p[i])下的值,就可以(O(2))快速幂。

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const int N = 50005;
    
    int n, m, sp, c;
    int v[N];
    
    int phi(int n) {
    	if(n == 1) return 1;
    	int s = n;
    	for(int x = 2; x * x <= n; x ++) if(n % x == 0) {
    		s = s / x * (x - 1);
    		for(; n % x == 0; n /= x);
    	}
    	if(n > 1) s = s / n * (n - 1);
    	return s;
    }
    
    int p[N], p0;
    
    namespace sub1 {
    	struct P {
    		ll x; int y;
    		P(ll _x = 0, int _y = 0) {
    			x = _x, y = _y;
    		}
    	};
    	P mul(P a, P b, int mo) {
    		a.y |= b.y;
    		a.x *= b.x;
    		if(a.x >= mo) a.x %= mo, a.y = 1;
    		return a;
    	}
    	
    	const int M = 15000;
    	
    	P t1[100][M], t2[100][M];
    	
    	void build() {
    		fo(i, 1, p0) {
    			t1[i][0] = t2[i][0] = P(1 % p[1], 1 >= p[1]);
    			P w = P(c % p[i], c >= p[i]);
    			fo(j, 1, M) t1[i][j] = mul(t1[i][j - 1], w, p[i]);
    			w = t1[i][M];
    			fo(j, 1, M) t2[i][j] = mul(t2[i][j - 1], w, p[i]);
    		}
    	}
    	
    	P b[N];
    	ll calc(int *a, int a0) {
    		a0 = min(a0, p0);
    		b[a0] = P(a[a0] % p[a0], a[a0] >= p[a0]);
    		fd(i, a0 - 1, 1) {
    			int y = b[i + 1].x + (b[i + 1].y ? p[i + 1] : 0);
    			int z1 = y % M, z2 = y / M;
    			b[i] = mul(t1[i][z1], t2[i][z2], p[i]);
    		}
    		return b[1].x;
    	}
    }
    
    using sub1 :: calc;
    
    int a[N]; int a0;
    
    #define i0 i + i
    #define i1 i + i + 1
    ll t[N * 4]; int mi[N * 4];
    
    void bt(int i, int x, int y) {
    	if(x == y) {
    		t[i] = v[x] % p[1];
    		return;
    	}
    	int m = x + y >> 1;
    	bt(i0, x, m); bt(i1, m + 1, y);
    	t[i] = (t[i0] + t[i1]) % p[1];
    }
    int pl, pr, px;
    void add(int i, int x, int y) {
    	if(mi[i] >= p0 - 1 || y < pl || x > pr) return;
    	if(x == y) {
    		mi[i] ++;
    		a0 = mi[i] + 1;
    		fo(j, 1, a0 - 1) a[j] = c; a[a0] = v[x];
    		t[i] = calc(a, a0);
    		return;
    	}
    	int m = x + y >> 1;
    	add(i0, x, m); add(i1, m + 1, y);
    	t[i] = (t[i0] + t[i1]) % p[1];
    	mi[i] = min(mi[i0], mi[i1]);
    }
    void ft(int i, int x, int y) {
    	if(y < pl || x > pr) return;
    	if(x >= pl && y <= pr) {
    		px = (px + t[i]) % p[1];
    		return;
    	}
    	int m = x + y >> 1;
    	ft(i0, x, m); ft(i1, m + 1, y);
    }
    
    int op;
    
    int main() {
    	scanf("%d %d %d %d", &n, &m, &sp, &c);
    	p[p0 = 1] = sp;
    	while(p[p0] != 1) p0 ++, p[p0] = phi(p[p0 - 1]);
    	p[++ p0] = 1;
    	fo(i, 1, n) scanf("%d", &v[i]);
    	sub1 :: build();
    	bt(1, 1, n);
    	fo(ii, 1, m) {
    		scanf("%d %d %d", &op, &pl, &pr);
    		if(op == 0) {
    			add(1, 1, n);
    		} else {
    			px = 0;
    			ft(1, 1, n);
    			pp("%d
    ", px);
    		}
    	}
    }
    
  • 相关阅读:
    iOS 自带系统语音识别
    对iOS10新增Api的详细探究
    iOS 技术前瞻
    iOS 之 byte NSString NSData类型转换
    iOS 文本属性
    基本力
    xamarin mac 基础知识 之 界面
    xamarin mac 之 基础知识
    xamarin mac 之 资料
    I方法 thinkphp
  • 原文地址:https://www.cnblogs.com/coldchair/p/12716074.html
Copyright © 2020-2023  润新知