比赛 20241023 评测结果 AAAAAAAAAAAAAAA
题目名称 The 'Winning' Gene 最终得分 100
用户昵称 darkMoon 运行时间 5.566 s
代码语言 C++ 内存使用 25.00 MiB
提交时间 2024-10-23 10:11:58
显示代码纯文本
#include<bits/stdc++.h>
using namespace std;
auto IN = freopen("winninggene.in", "r", stdin);
auto OUT = freopen("winninggene.out", "w", stdout);
auto mread = [](){int x;scanf("%d", &x);return x;};
const int N = 3005, p = 127, MOD = 998244353;
int n = mread(), sum[N][N], ha[N][20], pw[N], ans[N], l[N], r[N];
char s[N];
int bal(int x, int y, int l){
    // 比较以 x 和 y 开头的两个长度为 l 的字符串
    // return ->   -1: x > y    0: x = y    1: x < y
    int sum = 0;
    for(int i = __lg(l); i >= 0; i --){
        if(sum + (1 << i) <= l && ha[x][i] == ha[y][i]){
            x += 1 << i;
            y += 1 << i;
            sum += 1 << i;
        }
    }
    if(sum == l){
        return 0;
    }
    else if(s[x] > s[y]){
        return -1;
    }
    else{
        return 1;
    }
}
signed main(){
    pw[0] = 1;
    for(int i = 1; i < N; i ++){
        pw[i] = pw[i - 1] * p % MOD;
    }
    scanf("%s", s + 1);
    for(int i = 1; i <= n; i ++){
        ha[i][0] = (s[i] - '0' + 1);
    }
    for(int j = 1; j <= 15; j ++){
        for(int i = 1; i <= n - (1 << j) + 1; i ++){
            ha[i][j] = (1ll * ha[i][j - 1] * pw[1 << j - 1] % MOD + ha[i + (1 << j - 1)][j - 1]) % MOD;
        }
    }
    stack<int> st;
    for(int i = 1; i <= n; i ++){
        // L 的值为 i,也就是胜利基因候选(小子串)的长度为 i
        while(st.size()){
            st.pop();
        }
        // 单调栈,作用是找出左边第一个字典序 小于等于 当前字符串的
        for(int j = 1; j <= n - i + 1; j ++){
            // L 是从 j 开始的,也就是 L = [j, j + i - 1]
            while(st.size()){
                int tmp = bal(st.top(), j, i);
                if(tmp == -1){
                    st.pop();
                }
                else{
                    break;
                }
            }
            if(st.size() == 0){
                l[j] = 0;
            }
            else{
                l[j] = st.top();
            }
            st.push(j);
        }
        while(st.size()){
            st.pop();
        }
        // 单调栈,作用是找出右面第一个字典序 小于 当前字符串的
        for(int j = n - i + 1; j >= 1; j --){
            // L 是从 j 开始的,也就是 L = [j, j + i - 1]
            while(st.size()){
                int tmp = bal(j, st.top(), i);
                if(tmp == 1 || tmp == 0){
                    st.pop();
                }
                else{
                    break;
                }
            }
            if(st.size() == 0){
                r[j] = n + 1;
            }
            else{
                r[j] = st.top() + i - 1;
            }
            st.push(j);
        }
        for(int j = 1; j <= n - i + 1; j ++){
            sum[i][i] ++;
            sum[i][r[j] - l[j] - 1 + 1] --;
        }
    }
    for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= n; j ++){
            sum[i][j] += sum[i][j - 1];
            ans[sum[i][j]] ++;
        }
    }
    for(int i = 1; i <= n; i ++){
        printf("%d\n", ans[i]);
    }
    return 0;
}