http://oj.acm.zstu.edu.cn/JudgeOnline/problem.php?id=4440

题解:

由于x,y,z 都是大于等于1 的,
所以原序列是升序的,但是注意给你的a[0],a[1]可能不是升序的(这里要特别处理)。
对于这些操作很容易发现较长的操作会覆盖掉较小的操作
所以如果一个操作的区间比它后面的某个操作的区间小,那么这个操作是无效的,
可以发现有效的操作的区间必定是递减的,
由于只会按照从大到小和从小到大排序,
而每个有效操作的有效区间是它下一个有效区间没有覆盖的部分,所以只需要把原序列
用双指针维护,每次把每个有效操作的有效区间填好就行了。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;

int v[N], q[N];
int line[N];
int ans[N];
int n, qq;
int main(){
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);
    int t, x, y, z;
    scanf("%d", &t);
    while(t--){
        scanf("%d%d%d%d%d%d%d", &v[1], &v[2], &x, &y, &z, &n, &qq);
        for(int i = 3; i <= n; ++i) 
            v[i] = (v[i - 1] * 1ll * x + y * 1ll * v[i - 2] + z) % mod;
        q[1] = v[1] % n + 1, q[2] = v[2] % n + 1;
        for(int i = 3; i <= qq; ++i) 
            q[i] = (y * 1ll * q[i - 1] + x * 1ll * q[i - 2] + z) % n + 1;
        int en = 0, l = 1, r;
        for(int i = qq; i ; --i){
            if(q[i] > line[en]) line[++en] = q[i];
        }
        if(line[en] >= 2 && v[1] > v[2])    swap(v[2], v[1]);
        for(int i = line[en] + 1; i <= n; ++i)  ans[i] = v[i];
        r = line[en];
        for(int i = en; i; --i){
            for(int j = line[i]; j > line[i - 1]; --j){
                if(line[i] & 1) ans[j] = v[l], l++;
                else    ans[j] = v[r], r--;
            }
        }
        LL aans = 0;
        for(int i = 1; i <= n; ++i){
            aans += ans[i] * 1ll * i % mod;
            if(aans >= mod) aans -= mod;
        }
        printf("%I64d\n", aans);
    }
    return 0;
}