题意:给出元素为[1,n]的排列a,定义f[l,r,k]为区间[l,r]内第k大的元素.
给出k,求 累加和(l=1~n,r~l~n)f[l,r,k] . n<=5e5,k<=min(80,n)
k<=80 a[i]贡献: 枚举左边有p个比它大,右边要有k-1-p个比它大.
如何处理出左/右边第p个比它大的位置?
从最小的数开始处理,链表初始满链,维护一个链表,当处理x时,链表中只有比x大的数
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+5; int a[N],b[N],n,k; int pre[N],nxt[N],pos[N]; ll solve(int x) { int c1=0,c2=0; for(int i=x;i&&c1<=k;i=pre[i]) a[++c1]=i-pre[i]; for(int i=x;i<=n&&c2<=k;i=nxt[i]) b[++c2]=nxt[i]-i; ll res=0; for(int i=1;i<=c1;i++) { if(c2>=k-i+1&&k-i+1>=1) res+=a[i]*b[k-i+1]; } return res; } void del(int x) { pre[nxt[x]]=pre[x]; nxt[pre[x]]=nxt[x]; } int main() { int T; cin>>T; while(T--) { int x; scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&x),pos[x]=i; ll ans=0; for(int i=0;i<=n+1;i++) pre[i]=i-1,nxt[i]=i+1; pre[0]=0,nxt[n+1]=n+1; for(int i=1;i<=n;i++) { ans+=i*solve(pos[i]); del(pos[i]); } printf("%lld\n",ans); } return 0; }
6058 Kanade's sum 链表维护()
时间: 2024-10-01 20:29:01