有n个数,给定一个k,求所有长度大于等于k的区间中前k大数的总和。这样就比较简单相信大家都会,所以此题要求当k=1~n的总和,即求
∑nk=1∑n−k+1i=1∑nj=i+k−1 区间前K大和Input
输入五个数n,a1,A,B,C。a1表示第一个数,A,B,C用来生成其余n-1个数。a(i)=(a(i-1)*A+B)mod C。1<=n<=1,000,000,0<=a1,A,B,C<=1,000,000,000
Output
一个数表示答案,最后答案对1,000,000,007取模。
Input示例
3 3 1 1 10
Output示例63样例解释:
三个数为3,4,5 K=1:[1,1]=3,[1,2]=[2,2]=4,[1,3]=[2,3]=[3,3]=5(表示各个区间在k=1时的答案) K=2:[1,2]=7,[2,3]=[1,3]=9 K=3:[1,3]=12
题目大意:求sigma(k=1--n) f(k),k为区间大于等于k的前k大的和。
题解:树状数组
对于区间[l,r],假设它的答案为ans,如果新增一个数a[r+1],那么它
出现的次数就是[l,r]中小于它的数的个数。如果Ai<Aj,i<j,那么包含这两个数
的区间的个数为i*(n-j+1),则对答案的贡献为Aj*(n-j+1),对于Aj>Ai,i>j,
倒过来再处理一遍。注意:双关键字排序
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define mod 1000000007 #define maxn 1000009 #define LL long long using namespace std; LL n,ans,A,B,C,a[maxn],tree[maxn]; typedef pair<LL,int> PII; PII b[maxn]; void add(int x,int p){ for(;x<=n;x+=x&(-x))tree[x]=(tree[x]+p)%mod; } LL getsum(int x){ LL all=0; for(;x;x-=x&(-x))all=(all+tree[x])%mod; return all; } int main(){ scanf("%lld%lld%lld%lld%lld",&n,&a[1],&A,&B,&C); b[1].first=a[1];b[1].second=1; for(int i=2;i<=n;i++){ a[i]=(a[i-1]*A+B)%C; b[i].first=a[i];b[i].second=i; } sort(b+1,b+n+1); for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+n+1,make_pair(a[i],i))-b; for(int i=1;i<=n;i++){ add(a[i],i); LL tmp=b[a[i]].first*1LL*(n-i+1)%mod; LL amp=getsum(a[i]); ans=(ans%mod+tmp*amp%mod)%mod; } memset(tree,0,sizeof(tree)); for(int i=n;i>=1;i--){ LL tmp=(b[a[i]].first*1LL*i)%mod; LL amp=getsum(a[i]); ans=(ans%mod+tmp*amp%mod)%mod; add(a[i],n-i+1); } printf("%lld ",ans); return 0; }