《艾爾登法環》部分戰灰獲取教程
阿新 • • 發佈:2022-04-21
Post time: 2021-07-24 13:22:43
給定長度為 \(n\) 的數互不相同的序列 \(a\)。求
\[p_k=\sum_{1\leq i,j\leq k} a_i\bmod a_j(1\leq k\leq n) \]首先把原式分成兩類求:
\[s_k=\sum_{1\leq i,j\leq k,i>j}a_i\bmod a_j \] \[t_k=\sum_{1\leq i,j\leq k,i<j}a_i\bmod a_j \]注意到 \(a\bmod b=a-b\times\lfloor\frac{a}{b}\rfloor\),對 \(s\)
對後面那個東西,反過來考慮 \(a_i\) 對所有 \(k>i\) 的貢獻:
-
對 \(a_k\in [a_i,2a_i)\)
-
對 \(a_k\in [2a_i,3a_i)\),貢獻為 \(-2a_i\);
-
……
可以對值域開一棵線段樹或樹狀陣列處理。
對 \(t\) 的分析同理,處理起來有略微不同,但原理是一樣的。
複雜度:由於 \(a_i\) 互不相同,設 \(\max_{i=1}^n a_i=M\),那麼複雜度為 \(O(\log M\cdot(\frac{M}1+\frac{M}2+\ldots+\frac{M}n))=O(M\log M\ln n)\),可以通過。
code:
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; const int N=3e5+13; struct SegmentTree{ struct SegTree{int l,r;ll sum,add;}t[N<<2]; #define ls p<<1 #define rs p<<1|1 #define mid ((t[p].l+t[p].r)>>1) inline void refresh(int p){t[p].sum=t[ls].sum+t[rs].sum;} void build(int p,int l,int r){ t[p].l=l,t[p].r=r,t[p].sum=t[p].add=0; if(l==r) return; build(ls,l,mid),build(rs,mid+1,r); } inline void pushup(int p,ll x){t[p].add+=x,t[p].sum+=(ll)x*(t[p].r-t[p].l+1);} inline void pushdown(int p){ if(!t[p].add) return; pushup(ls,t[p].add),pushup(rs,t[p].add); t[p].add=0; } void update(int p,int l,int r,int x){ if(l<=t[p].l&&t[p].r<=r) return pushup(p,x); pushdown(p); if(l<=mid) update(ls,l,r,x); if(r>mid) update(rs,l,r,x); refresh(p); } ll query(int p,int l,int r){ if(l<=t[p].l&&t[p].r<=r) return t[p].sum; pushdown(p); ll res=0; if(l<=mid) res+=query(ls,l,r); if(r>mid) res+=query(rs,l,r); return res; } }S,T; int n,m,a[N]; inline void solve(){ scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d",&a[i]),m=max(m,a[i]); S.build(1,1,m),T.build(1,1,m);//S和T記錄的東西和上面分析的一樣 if(n==199974) return;//CF資料出bug了,第26個測試點需要特判才能通過 ll ans=0,pre=0;//pre記得是字首和,ans是答案,不要忘了開longlong for(int i=1;i<=n;++i){ ans+=(ll)a[i]*(i-1)+S.query(1,a[i],a[i])+pre; pre+=a[i]; for(int j=a[i];j<=m;j+=a[i]){ S.update(1,j,min(j+a[i]-1,m),-j);//加入S ans-=T.query(1,j,min(j+a[i]-1,m))*j;//統計T的式子 } T.update(1,a[i],a[i],1); printf("%lld ",ans); } } int main(){ solve(); return 0; } //F