AtCoder ABC 221 D
阿新 • • 發佈:2021-10-07
題目分析
不難分析出來,我們就是要求出,對每一個位置i
而言,其後面的比它大的位置j1
,j2
.....jn
,構成的數學式子求解。
我們可以對式子進行化簡。
\[ans[i]=\frac{2^{j_1-1}+2^{j_2-1}+...2^{j_n-1}}{2_i} \]然後,emm,我就卡在這裡了,因為這時就要求出i之後所有比它大的位置。
但是,我忽略了一個很重要的思想,正著想不行的時候,我們可以嘗試反著想。
如果,我們要求的是一個數前面所有比它小的位置
,會有出路嘛?
我們可以很快的發現,當要找一個數前面比他小的位置來求答案時,我們要求的式子就變成了
那接下來要解決的問題就是,括號裡面的怎麼求?
這時,就簡單了,我們可以用樹狀陣列進行優化。在樹狀陣列中,考慮每個位置時,在w[j]上插入對應的式子。這樣正向掃描時,這樣sum(w[j])就是前面比它小的位置上就是對應的式子的和(即括號裡的內容)了。
AcCode
#include<iostream> #include<cmath> #include<map> using namespace std; typedef long long LL; const LL N = 3e5 + 10,mod=998244353; LL tr[N]; int w[N]; int n; int lowbit(int x) { return x & (-x); } void add(int x,LL c) { for(int i=x;i<=n;i+=lowbit(i)) { tr[i]=(tr[i]+c)%mod; } } LL sum(int x) { LL res = 0; for(int i=x;i;i-=lowbit(i)) { res=(res+tr[i])%mod; } return res; } LL ksm(LL a,LL b) { LL res = 1; while(b) { if(b&1) res=res*a%mod; b>>=1; a=a*a%mod; } return res; } void init() { map<int,int> mp; for(int i=1;i<=n;i++) mp[w[i]]=0; int sz=0; for(auto &p:mp) p.second=++sz; for(int i=1;i<=n;i++) w[i]=mp[w[i]]; } int main() { const LL div = ksm(2,mod-2); cin>>n; for(int i=1;i<=n;i++) cin>>w[i]; LL ans = 0; init(); for(int i=1; i<=n; i++){ ans += sum(w[i])*ksm(2,i-1); ans %= mod; add(w[i],ksm(div,i)); } cout<<ans<<endl; return 0; }