题意:略
思路:要我们求每个区间第K大数之和,其实可以转换为求多少个区间的第K大数是X,然后我们在求和就好了。
那么我们可以从小到大枚举所有可能成为第K大的数。为什么从小到大呢?
因为从小到大我们就略去了大小的比较了,后面我们维护的链表就要把这个值除去。
/* gyt Live up to every day */ #include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<stack> #include<cstring> #include<queue> #include<set> #include<string> #include<map> #include <time.h> #define PI acos(-1) using namespace std; typedef long long ll; typedef double db; const int maxn = 510000+10; const ll maxm = 1e7; const int modd = 10000007; const int INF = 1<<30; const db eps = 1e-9; int pos[maxn], pre[maxn], nex[maxn]; void solve() { int n, k; scanf("%d%d", &n, &k); for (int i=1; i<=n; i++) { int x; scanf("%d", &x); pos[x]=i; pre[i]=i-1, nex[i]=i+1; } pre[0]=0; nex[n+1]=n+1; ll sum=0; for (int j=1; j<=n; j++) { int x=pos[j]; int rq[110]; int lc=0, rc=0; // cout<<"x:"<<x<<endl; for (int i=x; i<=n&&rc<k; i=nex[i]) { rq[++rc]=nex[i]-i; // cout<<nex[i]<<" "<<i<<endl; } ll ans=0; for (int i=x; i>0&&lc<k; i=pre[i]) { lc++; int r=k-lc+1; if (r>rc) continue; ans+=(i-pre[i])*rq[r]; //前面有多少个比他小的数,我们就可以构成那么多的区间 //cout<<"ans:"<<ans<<endl; //cout<<(i-pre[i])<<" "<<rq[r]<<endl; } //cout<<"rc:"<<rc<<" lc:"<<lc<<endl; sum+=ans*j; pre[nex[x]]=pre[x]; nex[pre[x]]=nex[x]; //cout<<j<<" "<<ans<<endl; //cout<<"---------------"<<endl; } cout<<sum<<endl; } int main() { int t = 1; //freopen("in.txt", "r", stdin); scanf("%d", &t); //getchar(); while(t--) solve(); return 0; }
hdu-6058 Kanade's sum
时间: 2024-09-30 19:05:06