P4145 上帝造題的七分鐘2 / 花神遊歷各國 題解
阿新 • • 發佈:2020-07-18
簡要題意:
給定一個長為 \(n\) 的序列 \(a\),\(q\) 次操作:
- 對 \([l,r]\) 區間進行開平方操作。即 \(a_i \gets \lfloor \sqrt{a_i} \rfloor (i \in [l,r])\)..
- 詢問 \([l,r]\) 區間的和。即 \(a_{i=l}^r\) 的和。
\(n,q \leq 10^5\), \(1 \leq a_i \leq 10^{12}\)
我們注意到一個性質:
開平方運算元將會很快變成 \(1\). 即使是 \(10^{12}\),在 六次開平方操作之後 也變成了 \(1\).
所以修改操作 有效的次數
我們可以維護字首和 \(s\),暴力維護!但如果 \(a_{i=l}^r a_i = r - l + 1\),說明 \(a_i = 1 (i \in [l,r])\),那麼可以跳過這個操作。
時間複雜度:\(\mathcal{O}(n)\).
實際得分:\(100pts\).
#pragma GCC optimize(2) #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+1; inline ll read(){char ch=getchar(); int f=1; while(!isdigit(ch)) {if(ch=='-') f=-f; ch=getchar();} ll x=0;while(isdigit(ch)) x=x*10+ch-'0',ch=getchar(); return x*f;} int n,q; ll a[N],s[N]; int main() { n=read(); for(int i=1;i<=n;i++) a[i]=read(),s[i]=s[i-1]+a[i]; q=read(); while(q--) { int op=read(),l=read(),r=read(); if(l>r) swap(l,r); //細節 if(!op) { if(s[r]-s[l-1]==r-l+1) continue; else for(int i=l;i<=n;i++) { if(i<=r) a[i]=sqrt(a[i]); s[i]=s[i-1]+a[i]; } //暴力維護 } else printf("%lld\n",s[r]-s[l-1]); } return 0; }
後記
這個題可以用線段樹等維護字首和 \(s\),還可以大力線段樹。不過,本來修改只有 \(6\) 次有效,暴力也不怕!是不是!