2020牛客暑期多校训练营(第三场) H Sort the Strings Revision

思路:由于是字典序,所以肯定是越前面的字符对整体的字典序的影响越大,所以我们先看最小的 \(p[i]\) , 假设最小的 \(p[i] = st\) ,并且 \(d[i] != st \% 10\)

如果 \(d[i] < st \% 10\) , 那么 \(s_1 - s_i\) > \(s_{i + 1} - s_n\) ,大于则同理,这个手写一个样例就会理解,这样我们就把所有字符串分成了两个互相独立的字符串

集合,对于每个字符串子集,都可以用同样的办法处理,唯一的难点是要找出连续区间内最小的 \(p[i]\) ,这个可以用笛卡尔树处理,其实也可以线段树,

不过会被卡好像(队友试过)。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 2e6 + 60;
const int MOD = 1000000007;
int n;
int p[maxn], d[maxn], ls[maxn], rs[maxn];

int stk[maxn], top;
void dikaer(){
    top = 0;
    for(int i = 0; i < n; i++){
        if(d[i] == p[i] % 10) {
            continue;
        }
        int k = top;
        while(k > 0 && p[stk[k]] > p[i]) k--;
        if(k) rs[stk[k]] =  i;
        if(k < top) ls[i] = stk[k + 1];
        stk[++k] = i;
        top = k;
    }
}

LL pos[maxn];
void dfs(int le, int ri, int st){
    if(le == ri) return ;
    if(st == -1){
        for(int i = 0; i < ri - le + 1; i++){
            pos[le + i] += i;
            pos[le + i + 1] -= i;
        }
        return ;
    }
    if(d[st] > p[st] % 10){
        dfs(le, st, ls[st]);
        dfs(st + 1, ri, rs[st]);
        pos[st + 1] += (st - le + 1);
        pos[ri + 1] -= (st - le + 1);
    } else if(d[st] < p[st] % 10){
        dfs(le, st, ls[st]);
        dfs(st + 1, ri, rs[st]);
        pos[le] += (ri - st);
        pos[st + 1] -= (ri - st);
    }
}

int main()
{  
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%d", &n);
        int seed, a, b, mod;
        scanf("%d%d%d%d", &seed, &a, &b, &mod);
        int nsed = seed;
        for(int i = 0; i <= n; i++){
            stk[i] = -1;
            pos[i] = 0;
            ls[i] = rs[i] = -1;
            p[i] = i;
        }
        for(int i = 1; i < n; i++){
            swap(p[nsed % (i + 1)], p[i]);
            nsed = (1LL * nsed * a + b) % mod; 
        }
        scanf("%d%d%d%d", &seed, &a, &b, &mod);
        nsed = seed;
        for(int i = 0; i < n; i++){
            d[i] = nsed % 10;
            nsed = (1LL * nsed * a + b) % mod;
        }
        dikaer();
        dfs(0, n, stk[1]);
        for(int i = 1; i <= n; i++){
            pos[i] += pos[i - 1];
        }
        LL x = 1;
        LL ans = 0;
        for(int i = 0; i <= n; i++){
            ans = (1LL * ans + 1LL * pos[i] * x % MOD) % MOD;
            x = 10000019LL * x % MOD;
        }
        printf("%lld\n", ans);
    }
    return 0;
}
posted @ 2020-07-26 16:59  从小学  阅读(142)  评论(0编辑  收藏  举报