[BZOJ 3654] 图样图森破

这里写图片描述

Solution :
把每个串和它们的反转拉一起求一个后缀数组,然后枚举回文串的中心,往回文串两边尽可能添加串,这个过程可以记忆化,如果转移中发现了环说明长度可以无限大。

吐槽:刚开始写的RMQ有点问题,怒改为暴力求lcp然后就A了…10s…..这题好 但是数据有待加强…….

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <bitset>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <iterator>
#include <vector>
#include <queue>
#include <set>
#include <map>

#define rep(i, x, y) for (int i = (x), _ = (y); i <= _; ++i)
#define down(i, x, y) for (int i = (x), _ = (y); i >= _; --i)
#define x first
#define y second
#define LX_JUDGE

using namespace std;
typedef long long LL;

template<typename T> inline void upMax(T & x, T y) { x < y ? x = y : 0; }
template<typename T> inline void upMin(T & x, T y) { x > y ? x = y : 0; }

template<typename T>
inline void read(T & x)
{
    char c;
    while ((c = getchar()) < '0' || c > '9') ;
    for (x = c - '0'; (c = getchar()) >= '0' && c <= '9'; x = x * 10 + c - '0') ;
}

const LL inf = 1e15;
const int N = 2e5 + 3e4;

namespace suffixArray
{
    int Sa[N], Rank[N], height[N];
    int mn[N][19], Log[N], tot;

    void suffixDa(char * r, int n, int m)
    {
        static int ws[N];
        int i, j, p, *x = Rank, *y = height;
        tot = n;

        memset(ws, 0, sizeof(int) * m);
        for (i = 0; i < n; ++i)
            ++ws[x[i] = r[i]];
        for (i = 1; i < m; ++i)
            ws[i] += ws[i - 1];
        for (i = n - 1; ~i; --i)
            Sa[--ws[x[i]]] = i;
        for (j = p = 1; p < n; j <<= 1, m = p)
        {
            for (p = 0, i = n - j; i < n; ++i)
                y[p++] = i;
            for (i = 0; i < n; ++i) if (Sa[i] >= j)
                y[p++] = Sa[i] - j;
            memset(ws, 0, sizeof(int) * m);
            for (i = 0; i < n; ++i)
                ++ws[x[i]];
            for (i = 1; i < m; ++i)
                ws[i] += ws[i - 1];
            for (i = n - 1; ~i; --i)
                Sa[--ws[x[y[i]]]] = y[i];
            swap(x, y);
            x[Sa[0]] = 0, p = 1;
            for (i = 1; i < n; ++i)
                x[Sa[i]] = (y[Sa[i - 1]] == y[Sa[i]] && y[Sa[i - 1] + j] == y[Sa[i] + j]) ? p - 1 : p++;
        }
        for (i = 0; i < n; ++i)
            Rank[Sa[i]] = i;
        for (i = p = 0; i < n - 1; ++i)
        {
            p ? --p : 0;
            j = Sa[Rank[i] - 1];
            while (r[i + p] == r[j + p]) 
                ++p;
            height[Rank[i]] = p;
        }
        height[0] = height[1] = height[n] = 0;

        rep (i, 2, n)
            Log[i] = Log[i >> 1] + 1;

        rep (i, 0, n - 1) 
            mn[i][0] = height[i];

        rep (i, 0, Log[n] - 1)
        {
            rep (j, 0, n - (1 << (i + 1)) + 1)
                mn[j][i + 1] = min(mn[j][i], mn[j + (1 << i)][i]);
        }
    }

    int Lcp(int x, int y)
    {
        if (x == y)
            return tot - x;
        x = Rank[x], y = Rank[y];
        if (x > y)
            swap(x, y);
        int k = Log[y - x];
        return min(mn[x + 1][k], mn[y - (1 << k) + 1][k]);
    }
}

char str[N];
int belong[N], start[211], last[211];
int n, m;

LL f[N];
bool ins[N];

LL calc(int x)
{
    using suffixArray::Lcp;

    if (str[x] < 'a')
        x = m;

    if (ins[x]) 
        return inf;
    else if (f[x] > 0) 
        return f[x];

    LL &ans = f[x];
    ins[x] = 1;

    if (x == m)
    {
        rep (i, 1, n + n)
            upMax(ans, calc(start[i]));
    }
    else 
    {
        int p = belong[x];

        rep (j, (p <= n ? n + 1 : 1), (p <= n ? n + n : n))
        {
            int t = min(Lcp(x, start[j]), min(last[p] - x, last[j] - start[j]));
            if (x + t == last[p])
                upMax(ans, calc(start[j] + t) + t * 2);
            else if (start[j] + t == last[j])
                upMax(ans, calc(x + t) + t * 2);
            else 
                upMax(ans, 2ll * t);
        }
    }

    upMax(ans, 0ll), upMin(ans, inf);
    ins[x] = 0;

    return ans;
}

int main()
{
#ifdef LX_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    read(n);

    rep (i, 1, n)
    {
        scanf("%s", str + m);
        start[i] = m;
        while (str[m])
            belong[m++] = i;
        last[i] = m;
        str[m++] = 'a' - 1;
    }

    int cur = 0;

    rep (i, n + 1, n + n)
    {
        start[i] = m;
        while (str[cur] >= 'a')
        {
            belong[m] = i;
            str[m++] = str[cur++];
        }
        last[i] = m;
        str[m++] = str[cur++];
        reverse(str + start[i], str + last[i]);
    }

    str[m++] = 0;
    suffixArray::suffixDa(str, m, 128);

    memset(f, -1, sizeof(f));

    LL ans = calc(m);

    rep (i, 1, n)
    {
        using suffixArray::Lcp;
        for (int j = start[i], k = last[i + n] - 1; j < last[i]; ++j, --k)
        {
            int tmp = min(Lcp(j, k), min(last[i] - j, last[i + n] - k));

            if (j + tmp == last[i])
                upMax(ans, calc(k + tmp) + 2 * tmp - 1);
            else if (k + tmp == last[i + n])
                upMax(ans, calc(j + tmp) + 2 * tmp - 1);
            else 
                upMax(ans, 2ll * tmp - 1);
        }
        for (int j = start[i] + 1, k = last[i + n] - 1; j < last[i]; ++j, --k)
        {
            int tmp = min(Lcp(j, k), min(last[i] - j, last[i + n] - k));

            if (j + tmp == last[i])
                upMax(ans, calc(k + tmp) + tmp * 2);
            else if (k + tmp == last[i + n])
                upMax(ans, calc(j + tmp) + tmp * 2);
            else 
                upMax(ans, 2ll * tmp);
        }
    }

    ans < inf ? printf("%lld\n", ans) : puts("Infinity");

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值