牛客挑战赛 80 C
*2200.
咋越来越喜欢打牛子了,谁叫主播一直去低端场炸鱼还一直没虐成弘文了。看来就是菜。
C 这一坨东西一看就很不可拆,要是和我一样一直想着拆贡献就错完了。正解是 朴素地做 + 一坨等比数列推柿子,直接得令人难绷。
最朴素的想法,考虑 \(1\) 到 \(v-1\) 这几个数出现的最左边出现的位置 \(l\) 和最右边的位置 \(r\),再讨论 \(v\) 出现的位置 \(p\)。
最朴素的讨论,考虑让 \(1\) 到 \(v-1\) 出现在区间里而 \(v\) 不出现。
如果 \(l<p<r\) 那就直接叉掉了。
如果 \(p<l\),那么左端点可以取在 \((p,l]\),右端点可以取在 \([r,n]\)。考虑直接枚举左端点的位置(这样只会贡献 \(O(n)\))并计算所有右端点的贡献之和。\(p>r\) 同理。
最后我们要算的柿子形如 \(\sum_{i=a}^{b} 2^{iv}\times i \times v\)。
后面那个 \(v\) 放到最后乘,然后设 \(x=2^v\),然后考虑前缀和思想,我们要算的变成了 \(\sum_{i=1}^{n} x^{i}\times i\)。注意到这个柿子等比数列很可推。
原式 = \(\sum_{i=1}^{n}\sum_{j=i}^{n} x^{i}\)
= \(\sum_{i=1}^{n}(\sum_{j=1}^{n} x^{i}-\sum_{j=1}^{i-1} x^{i})\)
= \(\sum_{i=1}^{n}(\frac{1-x^{n+1}}{1-x}-\frac{1-x^{i}}{1-x})\)
= \(\frac{(1-x^{n+1})\times n+\sum_{i=1}^{n}x^i-n}{1-x}\)
= \(\frac{(1-x^{n+1})\times n+\frac{1-x^{n+1}}{1-x}-n-1}{1-x}\)
直接快速幂算这个东西即可。于是我们会算了 \(\sum_{i=a}^{b} 2^{iv}\times i \times v\),这题就做完了。
最后要注意的是记得算上区间 [1,n] 的贡献和比较特殊的 \(v=1\) 的贡献。
#include <bits/stdc++.h>
//taskkill /f /im 未命名1.exe
#define ED cerr<<endl;
#define TS cerr<<"I AK IOI"<<endl;
#define cr(x) cerr<<x<<endl;
#define cr2(x,y) cerr<<x<<" "<<y<<endl;
#define cr3(x,y,z) cerr<<x<<" "<<y<<" "<<z<<endl;
#define cr4(x,y,z,w) cerr<<x<<" "<<y<<" "<<z<<" "<<w<<endl;
#define popcnt __builtin_popcount
#define all(s) s.begin(),s.end()
#define bstring basic_string
//#define add(x,y) (x+=y)%=mod
#define pii pair<int,int>
#define epb emplace_back
#define pb push_back
#define mk make_pair
#define ins insert
#define fi first
#define se second
#define ll long long
//#define ull unsigned long long
using namespace std;
const int N=2e5+5,INF=2e9,mod=998244353;
int t,n,m;
int a[N],ps[N];ll pw[N];
ll qpow(ll x,int y=mod-2) {
ll res=1;
while(y) {
if(y&1) res=res*x%mod;
x=x*x%mod,y>>=1;
}
return res;
}
ll sol(ll x,int r) {
ll v=1-qpow(x,r+1)+mod,div=qpow(1-x+mod);
return (v*r%mod+v*div%mod+mod-r-1+mod)*div%mod;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) {
scanf("%d",&a[i]);
ps[a[i]]=i;
}
pw[0]=1;
for(int i=1;i<=n+1;++i) {
pw[i]=pw[i-1]*2%mod;
}
ll ans=0;
int p=ps[1],mx=p,mi=p;
for(int i=1;i<=p;++i) {
ans=(ans+sol(2,p-i))%mod;
}
for(int i=p+1;i<=n;++i) {
ans=(ans+sol(2,n-i+1))%mod;
}
for(int i=2;i<=n;++i) {
p=ps[i];
if(p>=mi&&p<=mx) continue;
else if(p<mi) {
for(int j=p+1;j<=mi;++j) {
ans=(ans+i*(sol(pw[i],n-j+1)-sol(pw[i],mx-j)+mod))%mod;
}
}
else {
for(int j=mx;j<p;++j) {
ans=(ans+i*(sol(pw[i],j)-sol(pw[i],j-mi)+mod))%mod;
}
}
mx=max(mx,p),mi=min(mi,p);
}
printf("%lld\n",(ans+qpow(pw[n],n+1)*n%mod*(n+1)%mod)%mod);
return 0;
}