【hdu5152 A Strange Problem】【數論】【尤拉降冪】【線段樹】【單點修改】【好題】
阿新 • • 發佈:2018-12-24
【連結】
【題意】
給你一個長度為n的序列,有m個操作,3種操作:
1. 給你l,r,輸出l-r的和。
2. 修改操作,x,把a[x]->修改為x^a[x]
3. 加操作。l,r,x,l-r區間加x
輸出結果對2333333取模。
【思路】
重點在於第二個操作。
A^x = A ^ (x%Phi(C) + Phi(C)) (mod C) (x >= Phi(C))
然後,值得注意是,這道題的Phi(c),是一層套一層的。
最後,題目給出2333333(不是質數),所以Phi(c),最多隻有18層。
【程式碼】
#include<bits/stdc++.h> using namespace std; #define ll long long const int maxn = 100005; const int MOD = 2333333; int mo[19] = { 2333333 , 2196720 , 580608 , 165888 , 55296 , 18432 , 6144 , 2048 , 1024 , 512 , 256 , 128 , 64 , 32 , 16 , 8 , 4 , 2 , 1 }; ll sum[maxn << 2]; ll len[maxn << 2]; ll add[maxn << 2]; ll a[maxn]; vector<ll> v[maxn]; int n, m; int qpow(ll a, ll b, ll mod) { ll ret = 1; a %= MOD; while (b) { if (b & 1) ret = ret * a % mod; a = a * a % mod; b >>= 1; } return ret; } void pushdown(int n) { if (add[n]) { add[n<<1] += add[n]; add[n<<1|1] += add[n]; sum[n<<1] = (sum[n<<1] + add[n] * len[n<<1] % MOD) % MOD; sum[n<<1|1] = (sum[n<<1|1] + add[n] * len[n<<1|1] % MOD) % MOD; add[n] = 0; } } void pushup(int n) { sum[n] = (sum[n<<1] + sum[n<<1|1]) % MOD; } void build(int l, int r, int n) { add[n] = 0; len[n] = r - l + 1; if (l == r) { sum[n] = a[l] % MOD; return; } int mid = (l + r) >> 1; build(l, mid, n<<1); build(mid + 1, r, n<<1|1); pushup(n); } void pushupdate(int L, int R, int l, int r, int n, ll v) { if (L <= l && r <= R) { add[n] += v; sum[n] = (sum[n] + len[n] * v) % MOD; return; } pushdown(n); int mid = (l + r) >> 1; if (L <= mid) pushupdate(L, R, l, mid, n<<1, v); if (mid < R) pushupdate(L, R, mid + 1, r, n<<1|1, v); pushup(n); } ll cal(int i, int t) { if (t == 19) return 0; ll tmp; int ch = v[i].size() - 1 - t; if (t + 1 == v[i].size()) tmp = v[i][ch]; else tmp = qpow(2, cal(i, t + 1), mo[t]) + v[i][ch]; if (tmp >= mo[t]) tmp = tmp % mo[t] + mo[t]; return tmp; } void modify(int x, int l, int r, int n) { if (l == r) { v[x][v[x].size() - 1] += add[n]; add[n] = 0; v[x].push_back(0); sum[n] = cal(x, 0) % MOD; return; } pushdown(n); int mid = (l + r) >> 1; if (x <= mid) modify(x, l, mid, n<<1); else modify(x, mid + 1, r, n<<1|1); pushup(n); } ll query(int L, int R, int l, int r, int n) { if (L <= l && r <= R) return sum[n]; pushdown(n); int mid = (l + r) >> 1; ll ret = 0; if (L <= mid) ret = (ret + query(L, R, l, mid, n<<1)) % MOD; if (mid < R) ret = (ret + query(L, R, mid + 1, r, n<<1|1)) % MOD; return ret; } void init() { for (int i = 0; i <= n; ++i) v[i].clear(); } int main() { while (~scanf("%d%d", &n, &m) ) { init(); for (int i = 1; i <= n; ++i) { scanf("%lld", &a[i]); v[i].push_back(a[i]); } build(1, n, 1); int op, u, v; ll w; for (int i = 0; i<m; ++i) { scanf("%d", &op); if (op == 1) { scanf("%d%d", &u, &v); printf("%lld\n", query(u, v, 1, n, 1)); } else if (op == 2) { scanf("%d", &u); modify(u, 1, n, 1); } else{ scanf("%d%d%lld", &u, &v, &w); pushupdate(u, v, 1, n, 1, w); } } } }