zoukankan      html  css  js  c++  java
  • Codeforces 1114F(欧拉函数、线段树)

    AC通道

    要点

    • 欧拉函数对于素数有一些性质,考虑将输入数据唯一分解后进行素数下的处理。
    • 对于素数(p)有:(phi(p^k)=p^{k-1}*(p-1)=p^k*frac{p-1}{p}),因此将(a_i)唯一分解后有:(phi(prod_{i=l}^ra_i)=prod_{i=l}^ra_i*prod_{p in P}frac{p-1}{p}),其中(P)([l,r])内的(a_i)分解后的素数集合。
    • 这样转化公式以后,就只需线段树维护一下区间乘积和区间是否有某素数即可,第二个维护可以使用bitset二进制串代表有没有。
    • (a_i)(x)都很小,可以预处理1~300范围内的所需数据。
    const int maxn = 4e5 + 5, mod = 1e9 + 7;
    int n, q;
    bst Mask[305];//bitset
    vector<int> primes, invp;
    
    int ksm(int a, int b) {
    	int res = 1;
    	for (; b; b >>= 1) {
    		if (b & 1)	res = (ll)res * a % mod;
    		a = (ll)a * a % mod;
    	}
    	return res;
    }
    
    void pre(int n) {
    	bool vis[305] = {false};
    	for (int i = 2; i <= n; i++) {
    		if (!vis[i]) {
    			primes.push_back(i);
    			invp.push_back(ksm(i, mod - 2));
    			for (int j = i * i; j <= n; j += i) {
    				vis[j] = true;
    			}
    		}
    	}
    	for (int i = 1; i <= n; i++) {
    		for (int j = 0; j < primes.size(); j++) {
    			if (i % primes[j] == 0) {
    				Mask[i][j] = 1;
    			}
    		}
    	}
    }
    
    class SegmentTree {
    public:
    	#define ls(p) p << 1
    	#define rs(p) p << 1 | 1
    	
    	struct Node {
    		int l, r, mul, tag;
    		bst bits, laz;
    	}t[maxn * 3];
    
    	void Push_up(int p) {
    		t[p].mul = (ll)t[ls(p)].mul * t[rs(p)].mul % mod;
    		t[p].bits = t[ls(p)].bits | t[rs(p)].bits;
    		t[p].tag = 1;
    		t[p].laz.reset();
    	}
    
    	void Deal(int son, int fa) {
    		t[son].mul = (ll)t[son].mul * ksm(t[fa].tag, t[son].r - t[son].l + 1) % mod;
    		t[son].bits |= t[fa].laz;
    		t[son].tag = (ll)t[son].tag * t[fa].tag % mod;
    		t[son].laz |= t[fa].laz;
    	}
    
    	void Push_down(int p) {
    		if (t[p].tag != 1 || t[p].laz.any()) {
    			Deal(ls(p), p), Deal(rs(p), p);
    			t[p].tag = 1, t[p].laz.reset();
    		}
    	}
    
    	void Build(int l, int r, int p) {
    		t[p].l = l, t[p].r = r;
    		if (l == r) {
    			cin >> t[p].mul;
    			t[p].tag = 1;
    			t[p].bits = Mask[t[p].mul];
    			t[p].laz.reset();
    			return;
    		}
    		int mid = (l + r) >> 1;
    		Build(l, mid, ls(p));
    		Build(mid + 1, r, rs(p));
    		Push_up(p);
    	}
    
    	void Modify(int l, int r, int p, int x) {
    		if (l <= t[p].l && t[p].r <= r) {
    			t[p].mul = (ll)t[p].mul * ksm(x, t[p].r - t[p].l + 1) % mod;
    			t[p].tag = (ll)t[p].tag * x % mod;
    			t[p].bits |= Mask[x];
    			t[p].laz |= Mask[x];
    			return;
    		}
    		Push_down(p);
    		int mid = (t[p].l + t[p].r) >> 1;
    		if (l <= mid)	Modify(l, r, ls(p), x);
    		if (mid < r)	Modify(l, r, rs(p), x);
    		Push_up(p);
    	}
    	
    	friend Node operator + (const Node &A, const Node &B) {
    		Node tmp;
    		tmp.mul = (ll)A.mul * B.mul % mod;
    		tmp.bits = A.bits | B.bits;
    		return tmp;
    	}
    
    	Node Query(int l, int r, int p) {
    		if (l <= t[p].l && t[p].r <= r)
    			return t[p];
    		Push_down(p);
    		int mid = (t[p].l + t[p].r) >> 1;
    		if (mid >= r)	return Query(l, r, ls(p));
    		if (l > mid)	return Query(l, r, rs(p));
    		return Query(l, r, ls(p)) + Query(l, r, rs(p));
    	}
    }T;
    
    int main() {
    	ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    
    	pre(300);
    	cin >> n >> q;
    	T.Build(1, n, 1);
    	while (q--) {
    		string s;
    		int l, r, x;
    		cin >> s >> l >> r;
    
    		if (s == "MULTIPLY") {
    			cin >> x;
    			T.Modify(l, r, 1, x);
    		} else {
    			auto res = T.Query(l, r, 1);
    			int ans = res.mul;
    			for (int j = 0; j < primes.size(); j++) {
    				if (res.bits[j]) {
    					ans = (ll)ans * (primes[j] - 1) % mod * invp[j] % mod;
    				}
    			}
    			cout << ans << '
    ';
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    树状数组
    线段树
    最短路(FLOYD)
    欧拉函数
    筛素数
    并查集
    背包方案数问题(礼物)
    [BeijingWc2008]雷涛的小猫
    受欢迎的牛[HAOI2006]
    删除物品[JLOI2013]
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/10716317.html
Copyright © 2011-2022 走看看