有n个数,给定一个k,求所有长度大于等于k的区间中前k大数的总和。这样就比较简单相信大家都会,所以此题要求当k=1~n的总和,即求
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
题意:
求出所有区间前1大,前2大,前3大...前n大的数的和,当然前提是某个区间有足够的数。
思路:考虑[l,r]区间的前1大~前r-l+1大的数之和为ans1,转移到区间[l,r+1],
它的ans2就是ans2=ans1+(x+1)*a[r+1]+y,
其中x是[l,r]小于等于a[r+1]的数量,y是[l,r]大于a[r+1]的数的和,画图模拟下就知道了。
令dp[i]为所有右界为i的区间的ans,那么对于[1,i-1]中小于等于a[i]的数a[j],显然贡献了j次;
对于[1,i-1]中大于a[i]的数a[k],贡献了a[k]*k次,最后加上a[i]自己贡献了一次。
这些值离散化后用BIT维护即可。
# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e6+3;
const LL mod = 1e9+7;
LL a[maxn+3], b[maxn+3], s[2][maxn+3], dp[maxn];
void update(int pos, LL val, int id)
{
for(int i=pos; i<=maxn; i+=i&-i)
{
s[id][i] += val;
if(s[id][i] >= mod) s[id][i] -= mod;
}
}
LL cal(int pos, int id)
{
LL res = 0;
for(int i=pos; i; i-=i&-i)
{
res += s[id][i];
if(res >= mod) res -= mod;
}
return res;
}
int main()
{
int n;
LL x, y, z;
scanf("%d%lld%lld%lld%lld",&n,&a[1],&x,&y,&z);
b[1] = a[1];
for(int i=2; i<=n; ++i)
b[i] = a[i] = (a[i-1]*x+y)%z;
sort(b+1, b+1+n);
LL ans = 0;
for(int i=1; i<=n; ++i)
{
int p = lower_bound(b+1,b+1+n,a[i])-b;
LL small = cal(p, 0), big = (cal(maxn, 1)-cal(p, 1)+mod)%mod;
dp[i] = (small+i)%mod*a[i]%mod + big;
dp[i] = (dp[i] + dp[i-1])%mod;
update(p, i, 0);
update(p, a[i]*i%mod, 1);
}
for(int i=1; i<=n; ++i)
{
ans += dp[i];
if(ans >= mod) ans -= mod;
}
printf("%lld\n",ans);
return 0;
}