P4145 上帝造題的七分鐘2 / 花神遊歷各國 題解
阿新 • • 發佈:2020-11-18
Description
"第一分鐘,X說,要有數列,於是便給定了一個正整數數列。
第二分鐘,L說,要能修改,於是便有了對一段數中每個數都開平方(下取整)的操作。
第三分鐘,k說,要能查詢,於是便有了求一段數的和的操作。
第四分鐘,彩虹喵說,要是noip難度,於是便有了資料範圍。
第五分鐘,詩人說,要有韻律,於是便有了時間限制和記憶體限制。
第六分鐘,和雪說,要省點事,於是便有了保證運算過程中及最終結果均不超過64位有符號整數型別的表示範圍的限制。
第七分鐘,這道題終於造完了,然而,造題的神牛們再也不想寫這道題的程式了。"
——《上帝造題的七分鐘·第二部》
所以這個神聖的任務就交給你了。
SimpleInput
第一行一個整數 \(n\),代表數列中數的個數。
第二行 \(n\) 個正整數,表示初始狀態下數列中的數。
第三行一個整數 \(m\),表示有 \(m\) 次操作。
接下來 \(m\) 行每行三個整數k,l,r,
k=0
表示給 \([l,r]\) 中的每個數開平方(下取整)k=1
表示詢問 \([l,r]\) 中各個數的和。
資料中有可能 \(l>r\),所以遇到這種情況請交換 \(l\) 和 \(r\)。
10
1 2 3 4 5 6 7 8 9 10
5
0 1 10
1 1 10
1 1 5
0 5 8
1 4 8
SimpleOutput
對於詢問操作,每行輸出一個回答。
19
7
6
資料範圍
對於 \(30\%\) 的資料 \(1\le n,m\le 10^3\) 數列中的數不超過 32767。
對於 \(100\%\) 的資料 \(1\le n,m\le 10^5\) 數列中的數不超過 \(10^{12}\)。
Solution
對於這道題目,我們考慮 分塊。
Q1:為什麼不會出現鬼才TLE
A1:因為對於極限資料 \(10^{12}\) 開 6 次平方根之後就會變成 1,所以只有大概 6 倍的常數,適當卡常就可以通過
Q2:如何分塊?
A2:暴力即可
由於過於鬼畜,所以直接放程式碼。
Code
#include <bits/stdc++.h> using namespace std; const int N = 100009; long long a[N],sum[N]; int l[N],r[N],belong[N]; bool visit[N]; int len,n,q,opt,L,R; template <class T> inline void read(T &x) { x = 0; char ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } } inline void modify(int L,int R) { if(belong[L] == belong[R]) { if(visit[belong[L]]) return; for(register int i = L;i <= R;++i) { sum[belong[L]] -= a[i]; a[i] = sqrt(a[i]); sum[belong[L]] += a[i]; } if(sum[belong[L]] == r[belong[L]] - l[belong[L]] + 1) visit[belong[L]] = 1; }else { for(register int i = belong[L] + 1;i < belong[R];++i) { if(visit[i]) continue; for(register int j = l[i];j <= r[i];++j) { sum[i] -= a[j]; a[j] = sqrt(a[j]); sum[i] += a[j]; } if(sum[i] == r[i] - l[i] + 1) visit[i] = 1; } for(register int i = L;i <= r[belong[L]];++i) { sum[belong[L]] -= a[i]; a[i] = sqrt(a[i]); sum[belong[L]] += a[i]; } for(register int i = l[belong[R]];i <= R;++i) { sum[belong[R]] -= a[i]; a[i] = sqrt(a[i]); sum[belong[R]] += a[i]; } if(sum[belong[L]] == r[belong[L]] - l[belong[L]] + 1) visit[belong[L]] = 1; if(sum[belong[R]] == r[belong[R]] - l[belong[L]] + 1) visit[belong[R]] = 1; } } inline long long query(int L,int R) { long long ans = 0; if(belong[L] == belong[R]) { for(register int i = L;i <= R;++i) ans = ans + a[i]; }else { for(register int i = belong[L] + 1;i < belong[R];++i) { ans = ans + sum[i]; } for(register int i = L;i <= r[belong[L]];++i) ans += a[i]; for(register int i = l[belong[R]];i <= R;++i) ans += a[i]; } return ans; } int main() { read(n); len = sqrt(n); for(register int i = 1;i <= n;++i) { read(a[i]); belong[i] = i / len; sum[belong[i]] += a[i]; if(!l[belong[i]]) l[belong[i]] = i; r[belong[i]] = i; } read(q); while(q--) { read(opt); read(L); read(R); if(L > R) swap(L,R); if(opt == 0) { modify(L,R); }else { printf("%lld\n",query(L,R)); } } return 0; }
其實當時交上去的時候,我還被卡常了 50pts,最後加了一點玄學才過,果然是人傻常數大。