• 【LOJ】#2078. 「JSOI2016」无界单词


    题解

    用所有的方案减去有界的方案

    我们规定两个前缀后缀相同时长度最短的,设长度为l,因为长度最短所以他们也是无界单词,可以递推

    (f[i] = sum_{j = 1}^{lfloor frac{i}{2} floor} f[j] * 2^{i - 2 * j})

    计算第k大的时候同理,只需要先对枚举的前缀求一遍next数组,更新f值,然后再统计的时候特判一下后缀需要占用一部分l长前缀的情况

    代码

    #include <bits/stdc++.h>
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define mp make_pair
    #define MAXN 505
    #define mo 99994711
    #define pb push_back
    #define eps 1e-8
    //#define ivorysi
    using namespace std;
    typedef long long int64;
    typedef unsigned int u32;
    typedef unsigned long long u64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;T f = 1;char c = getchar();
        while(c < '0' || c > '9') {
            if(c == '-') f = -1;
            c = getchar();
        }
        while(c >= '0' && c <= '9') {
            res = res * 10 - '0' + c;
            c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    int N;
    u64 f[105],K;
    char s[105];
    int nxt[105];
    u64 Calc(int l) {
        memset(nxt,0,sizeof(nxt));
        memset(f,0,sizeof(f));
        for(int i = 2 ; i <= l ; ++i) {
            int p = nxt[i - 1];
            while(p && s[p + 1] != s[i]) p = nxt[p];
            if(s[p + 1] == s[i]) nxt[i] = p + 1;
            else nxt[i] = 0;
        }
        for(int i = 1 ; i <= l ; ++i) {
            if(!nxt[i]) f[i] = 1;
        }
        for(int i = l + 1 ; i <= N ; ++i) {
            f[i] = 1LL << (i - l);
            for(int j = 1 ; j <= i / 2 ; ++j) {
                if(l + j <= i) {f[i] -= f[j] * (1LL << (i - j - max(l,j)));}
                else if(f[j]){
                    bool flag = 1;
                    for(int k = 1 ; k <= l - (i - j); ++k) {
                        if(s[k] != s[k + (i - j)]) {flag = 0;break;}
                    }
                    f[i] -= flag;
                }
            }
        }
        return f[N];
    }
    void Solve() {
        read(N);read(K);
        memset(f,0,sizeof(f));
        f[1] = 2;
        for(int i = 2 ; i <= N ; ++i) {
            f[i] = 1LL << i;
            if(i == 64) f[i] = 0;
            for(int j = 1 ; j <= i / 2 ; ++j) {
                f[i] -= f[j] * (1LL << (i - 2 * j));
            }
        }
        out(f[N]);enter;
        for(int i = 1 ; i <= N ; ++i) {
            s[i] = 'a';
            u64 x = Calc(i);
            if(K > x) {K -= x;s[i] = 'b';}
        }
        for(int i = 1 ; i <= N ; ++i) {
            putchar(s[i]);
        }
        enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        int T;
        read(T);
        while(T--) {Solve();}
        return 0;
    }
    
  • 相关阅读:
    linux系统如何发送邮件
    zabbix监测图形界面显示方框乱码解决方法
    Eclipse C++的配置问题launch failed binary not found
    Cpu表现出正弦曲线
    让cpu跑到100%的bat文件
    进程僵死
    华为一些笔试题~~~~零散总结
    数据库~~~投影与除操作
    C++连接Mysql数据库操作
    微软面试题目及答案
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9547436.html
Copyright © 2020-2023  润新知