"蔚来杯"2022牛客暑期多校训练营1 B Spirit Circle Observation

Spirit Circle Observation

https://ac.nowcoder.com/acm/contest/33186/B

B Spirit Circle Observation

感谢@RedreamMer 巨佬 找到了我题解中的致命错误

Updata by 2022/7/20 15:29

构造的数据

#include <bits/stdc++.h>
using namespace std;
int a = 1e5;
int main() {
    freopen("a.in", "w", stdout);
    string s;
    for (int i = 1; i <= a; ++i) s.push_back('0');
    s.push_back('1');
    for (int i = 1; i <= a; ++i) s.push_back('0');
    for (int i = 1; i <= a; ++i) s.push_back('9');
    std::cout << s.size() << '\n' << s << '\n';
    return 0;
}

SAMSAM求出endposendpos然后枚举最后一位不是99的情况

我们枚举的是上面一个节点,贡献是

i=1totj=08endpos(ch[i][j])×endpos(ch[i][j+1])×(len[i]len[Link[i])\sum_{i=1}^{tot}\sum_{j=0}^{8}endpos(ch[i][j])\times endpos(ch[i][j+1])\times (len[i]-len[Link[i])

接下来枚举A+c+999A+c+99\dots9B+(char)(c+1)+000B+(char)(c+1)+00\dots0配对的情况

就是SAMSAM上枚举每个节点下方的子节点

如枚举到节点 ii 然后就枚举o=ch[i][j],p=ch[i][j+1](0j8)o=ch[i][j],p=ch[i][j+1](0\le j\le 8) 然后就oo一直走99的那一边,pp一直走00的一边,边走边统计,计算方式如上

这样是暴力会被卡成O(n2)O(n^2)

alt

官方题解给出了明确的说法,p1,p2p1,p2 这样的关键点对只有nn个,ch[p1][9],ch[p2][0]ch[p1][9],ch[p2][0]最多也只有nn个,我们就用mapmap 暴力存下所有点对及下方字符串的endpos(x)×endpos(y)endpos(x)\times endpos(y) 然后计算即可

#include <bits/stdc++.h>
typedef long long LL;

const int N = 8e5 + 1000;
int ch[N][10], last = 1, siz[N], Link[N], tot = 1, len[N];
char s[N];
std::vector<int> G[N];

void insert(int c) {
    int o = ++ tot, p = last; len[o] = len[p] + 1; siz[o] = 1;
    for (; p && ch[p][c] == 0; p = Link[p]) ch[p][c] = o;
    if (!p) Link[o] = 1;
    else {
        int q = ch[p][c];
        if (len[q] == len[p] + 1) Link[o] = q;
        else {
            int nq = ++ tot;
            Link[nq] = Link[q];
            len[nq] = len[p] + 1;
            Link[q] = Link[o] = nq;
            memcpy(ch[nq], ch[q], sizeof(ch[nq]));
            for (;ch[p][c] == q; p = Link[p]) ch[p][c] = nq;
        }
    }
    last = o;
}

void dfs(int x) {
    for (auto y : G[x]) {
        dfs(y);
        siz[x] += siz[y];
    }
}

void Get() {
    for (int i = 2; i <= tot; ++ i) G[Link[i]].push_back(i);
    dfs(1);
}

std::map<std::pair<int, int>, LL> mp;

LL Get(int x, int y) {
    if (!x || !y) return 0;
    if (mp.find({x, y}) != mp.end()) return mp[{x, y}];
    return mp[{x, y}] += (LL)Get(ch[x][9], ch[y][0]) + (LL)siz[x] * siz[y];
}

void work() {
    LL ans = 0; siz[0] = 0; len[0] = -1;
    for (int i = 1; i <= tot; ++ i) {
        for (int j = 0; j < 9; ++ j) {
            int o = ch[i][j], p = ch[i][j + 1];
            ans += (LL)(siz[o] * siz[p] + Get(ch[o][9], ch[p][0])) * (len[i] - len[Link[i]]);
        }
    }
    std::cout << ans << std::endl;
}

int main() {
    int n;
    scanf("%d%s", &n, s + 1);
    for (int i = 1; i <= n; ++ i) insert(s[i] - 48);
    Get(); work();
    return 0;
}


原代码
#include <bits/stdc++.h>
typedef long long LL;

const int N = 8e5 + 1000;
int ch[N][10], last = 1, siz[N], Link[N], tot = 1, len[N];
char s[N];
std::vector<int> G[N];

void insert(int c) {
    int o = ++ tot, p = last; len[o] = len[p] + 1; siz[o] = 1;
    for (; p && ch[p][c] == 0; p = Link[p]) ch[p][c] = o;
    if (!p) Link[o] = 1;
    else {
        int q = ch[p][c];
        if (len[q] == len[p] + 1) Link[o] = q;
        else {
            int nq = ++ tot;
            Link[nq] = Link[q];
            len[nq] = len[p] + 1;
            Link[q] = Link[o] = nq;
            memcpy(ch[nq], ch[q], sizeof(ch[nq]));
            for (;ch[p][c] == q; p = Link[p]) ch[p][c] = nq;
        }
    }
    last = o;
}

void dfs(int x) {
    for (auto y : G[x]) {
        dfs(y);
        siz[x] += siz[y];
    }
}

void Get() {
    for (int i = 2; i <= tot; ++ i) G[Link[i]].push_back(i);
    dfs(1);
}

void work() {
    LL ans = 0; siz[0] = 0; len[0] = -1;
    for (int i = 1; i <= tot; ++ i) {
        for (int j = 0; j < 9; ++ j) {
            int o = ch[i][j], p = ch[i][j + 1];
            while (o && p) {
                ans += ((LL)siz[o] * siz[p]) * (LL)(len[i] - len[Link[i]]);
                o = ch[o][9];
                p = ch[p][0];
            }
        }
    }
    std::cout << ans << std::endl;
}

int main() {
    int n;
    scanf("%d%s", &n, s + 1);
    for (int i = 1; i <= n; ++ i) insert(s[i] - 48);
    Get(); work();
    return 0;
}
全部评论
int a = 1e5; signed main() { freopen("in.in", "w", stdout); ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); string s; for(int i = 1; i <= a; ++i) s.push_back('0'); s.push_back('1'); for(int i = 1; i <= a; ++i) s.push_back('0'); for(int i = 1; i <= a; ++i) s.push_back('9'); cout << s.size() << '\n' << s << '\n'; return 0; }
1 回复 分享
发布于 2022-07-20 09:59
感谢 @zhoukangyang 神仙的数据/bx/bx/bx
1 回复 分享
发布于 2022-07-20 09:58
复杂度是假的,可以卡成 n ^ 2
1 回复 分享
发布于 2022-07-20 09:57
请问一下 map 做法里 {x, y} 点对的个数是如何保证的呢?题解里指出了关键点个数 O(n),但是关键点的对数却不一定有保证,这个细节还烦请大佬赐教
点赞 回复 分享
发布于 2022-07-22 20:19
assert 一下可以发现一个点作为 o和p 被访问的最大次数甚至是超过 100 的。这个做法实际上是暴力(但看起来不是很好卡
点赞 回复 分享
发布于 2022-07-19 14:18

相关推荐

来,说点可能被同行“骂”的大实话。🙊当初接数字马力Offer时,朋友都说:“蚂蚁的“内包”公司?你想清楚啊!”但入职快一年后的今天,我反而对他有了不一样的看法!🔹&nbsp;是偏见?还是信息差!之前没入职之前外面都在说什么岗位低人一等这类。实际上:这种情况不可至否,不能保证每个团队都是其乐融融。但我在的部门以及我了解的周边同事都还是十分好相处的~和蚂蚁师兄师姐之间也经常开一些小玩笑。总之:身份是蚂蚁公司给的,地位是自己挣的(一个傲娇女孩的自述)。🔹&nbsp;待遇?玩的就是真实!试用期工资全额发!六点下班跑得快(早9晚6或者早10晚7,动态打卡),公积金顶格交。别听那些画饼的,到手的钱和下班的时间才是真的(都是牛马何必难为牛马)。🔹&nbsp;能不能学到技术?来了就“后悔”!我们拥有权限直通蚂蚁知识库,技术栈多到学不完。说“学不到东西”的人,来了可能后悔——后悔来晚了(哈哈哈哈,可以不学但是不能没有)!💥&nbsp;内推地址:https://app.mokahr.com/su/ueoyhg❗我的内推码:NTA6Nvs走我的内推,可以直达业务部门,面试流程更快速,进度可查!今天新放HC,之前挂过也能再战!秋招已经正式开始啦~机会就摆在这,敢不敢来试一试呢?(和我一样,做个勇敢的女孩)
下午吃泡馍:数字马力的薪资一般哇,5年经验的java/测试就给人一万出头,而且刚入职第三天就让人出差,而且是出半年
帮你内推|数字马力 校招
点赞 评论 收藏
分享
冲鸭2024:亚信不去也罢
投递亚信科技(中国)有限公司等公司6个岗位
点赞 评论 收藏
分享
评论
9
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务