武汉大学2020年大学生程序设计大赛决赛C

Calculate the Sanity Value

https://ac.nowcoder.com/acm/contest/5523/C

这里介绍一种失了智的算法。
这种算法基于插桩原理。我们每隔len插一个庄,我们发现所有长度为len的子串都会和一个桩相交。然后对于每个长度len我们只要能够通过n/lenlog(len)的复杂度算出所有长度为len的SAN值就可以在nloglog的时间复杂度内解决问题。
这里有三个子问题:
1.如何判断[l1,r1]和[l2,r2]这两个子串是否相等,这里采用字符串哈希O(n)预处理 O(单次取模)查询。
2.如何判断过当前桩的所有子串和过前一个桩的子串有递增SAN值的关系,这里采用二分加哈希的方式来解决O(n)预处理 O(log*单次取模)的复杂度,也可以采用两次后缀数组的方式O(nlog)预处理 O(1)查询会更快一些。
3.如何处理长度为len的子串中某些san值递增,某些san值清零的问题。线段树O(log)处理

即使如此,你仍然无法通过此题,因为整体复杂度是O(nloglog*单次取模复杂度),%运算符是O(log)的,但是如今有取模黑科技可以比%运算符更加迅速,如此可以通过此题。

反正只要胆子大,常数卡卡就过了。

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

#define lson rt * 2
#define rson rt * 2 + 1

typedef long long ll;

const int N = 1e5 + 100;
const int MOD = 1e9 + 7;
const int SZ = 200;

typedef  unsigned  long long ull;
typedef __uint128_t L;

struct FastMod {
  ull b, m;
  FastMod(ull b) : b(b), m(ull((L(1) << 64) / b)) {}
  ull reduce(ull a) {
    return a - (ull)((L(m) * a) >> 64) * b;
  }
}F(MOD);

int tree[N * 4], laz[N * 4], flag[N * 4];

void push_down(int rt) {
    if (flag[rt]) {
        tree[lson] = laz[lson] = tree[rson] = laz[rson] = 0;
        flag[lson] = flag[rson] = 1;
        flag[rt] = 0;
    }
    laz[lson] += laz[rt];
    tree[lson] += laz[rt];
    laz[rson] += laz[rt];
    tree[rson] += laz[rt];
    laz[rt] = 0;
}

void insert(int rl, int rr, int l, int r, int rt) {
    if (rl == l && rr == r) {
        tree[rt]++;
        laz[rt]++;
        return;
    }
    push_down(rt);
    int m = (l + r) / 2;
    if (rr <= m) insert(rl, rr, l, m, lson);
    else if (m < rl) insert(rl, rr, m + 1, r, rson);
    else {
        insert(rl, m, l, m, lson);
        insert(m + 1, rr, m + 1, r, rson);
    }
    tree[rt] = max(tree[lson], tree[rson]) + laz[rt];
}

void clr(int rl, int rr, int l, int r, int rt) {
    if (rl == l && rr == r) {
        tree[rt] = laz[rt] = 0;
        flag[rt] = 1;
        return;
    }
    push_down(rt);
    int m = (l + r) / 2;
    if (rr <= m) clr(rl, rr, l, m, lson);
    else if (m < rl) clr(rl, rr, m + 1, r, rson);
    else {
        clr(rl, m, l, m, lson);
        clr(m + 1, rr, m + 1, r, rson);
    }
    tree[rt] = max(tree[lson], tree[rson]) + laz[rt];
}

int n;
char str[N];
ll pre[N], rff[N];

int qpow(int x, int n) {
    int r = 1;
    while (n > 0) {
        if (n & 1) r = 1LL * r * x % MOD;
        n /= 2;
        x = 1LL * x * x % MOD;
    }
    return r;
}

void init() {
    ll t = 1;
    for (int i = 1; i <= n; i++) {
        pre[i] = (pre[i - 1] + t * (str[i] - 'a')) % MOD;
        t = t * 26 % MOD;
    }
    int r = qpow(26, MOD - 2);
    rff[0] = 1;
    for (int i = 1; i <= n; i++) rff[i] = 1LL * rff[i - 1] * r % MOD;
}


/*int get(int l, int r) {
    if (r > n) return -1;
    int ans = 1LL * (pre[r] - pre[l - 1]) * rff[l - 1] % MOD;
    if (ans < 0) ans += MOD;
    return ans;
}*/


int get(int l, int r) {
    if (r > n) return -1; 
    int ans = F.reduce(F.reduce(pre[r] - pre[l - 1] + MOD) * rff[l - 1]);
    if (ans >= MOD) ans -= MOD;
    //printf("%d %d %d\n", l, r, ans);
    return ans;
}


void upd(int &x, int y) {
    if (y > x) x = y;
}

bool check(int l, int r, int d) {
    return get(l, r) == get(l + d, r + d);
}

int q1(int ql, int qr, int len) {
    if (str[ql] != str[ql - len]) return ql - 1;
    int m, l = ql, r = qr;
    while (r - l > 1) {
        m = (l + r) / 2;
        if (check(ql, m, -len)) l = m;
        else r = m;
    }
    if (check(ql, r, -len)) return r;
    return l;
}

int q2(int ql, int qr, int len) {
    if (str[qr] != str[qr - len]) return 1e9;
    int m, l = ql, r = qr;
    while (l < r) {
        m = (l + r) / 2;
        if (check(m, qr, -len)) r = m;
        else l = m + 1;
    }
    return l;
}

int main() {
    //freopen("0.txt", "r", stdin);
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%s", str + 1);
        n = strlen(str + 1);
        init();
        int ans = 0;
        for (int ma = 1; ma <= SZ && ma <= n; ma++) {
            for (int i = 1; i <= ma; i++) {
                int res = 1;
                for (int j = i; j <= n; j += ma) {
                    if (j - ma >= 1 && get(j - ma, j - 1) == get(j, j + ma - 1)) res++;
                    else {
                        upd(ans, res);
                        res = 1;
                    }
                }
                upd(ans, res);
            }
        }
        for (int sz = SZ + 1; sz <= n; sz++) {
            clr(1, sz, 1, sz, 1);
            for (int i = 2 * sz; i <= n; i += sz) {
                int l = q2(i - sz + 1, i, sz) - i + sz, r = q1(i, i + sz - 1, sz) - i + 1;
                if (r < l) {
                    clr(1, sz, 1, sz, 1);
                }
                else {
                    if (l > 1) clr(1, l - 1, 1, sz, 1);
                    if (r < sz) clr(r + 1, sz, 1, sz, 1);
                    insert(l, r, 1, sz, 1);
                }
                upd(ans, tree[1] + 1);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
全部评论

相关推荐

头像
02-21 16:31
长沙理工大学
大家好,今天分享一个很贴合目前校招时间段的提问:Up你好,本人双非本科大四,软件工程专业。大学前两年因为感觉前端好学,岗位也多选择学习前端。但那时比较懒散,课也多,所以前端也没有学多好。后来互联网寒冬,觉得出去不好找工作。就在大三下开始准备考研,但在去年10月份放弃考研(因为家里的一些事故,一个半月没有复习考研),处理好后,剩70多天感觉考不上值得上的学校。所以干脆准备就业,但感觉前端这个方向特别凉,于是换成了Linux&nbsp;c++方向(为此拒绝了一个前端实习)10月底到现在复习了c语言,学习了C++语法,特性,包括STL这些。学习了Linux系统编程进程线程,网络编程tcp/udp,多路转接,l...
牛客230000345号:毕业入坑两年,提点参考的东西吧,建议边找边备研,学历才是第一生产力,后期如果你要职业发展,这是最基本的几个了,工作和晋升除了项目经验,不就是比的派个人学历、吹牛能力和一堆头衔了(晋升的话,派系很重要)。 工作方面,不了解服务端,但是你可以看招聘,其实相比来说qt在客户端和服务端都可以用到,而且跨平台兼容性好,而且qt不就是c+++吗(学好c++,用哪个框架都不头痛),qt不只是给你个UI界面,封装的很多东西都是可以借鉴的。看你想去哪个城市,现在长沙软件行情不好,真心建议没上岸可以去深圳看看,长沙这边工资对标深圳砍半(眼泪流下来),长沙不少大一点私企面试的也开始卷学历卷项目(双非泪奔),如果想去国企你要能吹当然也可以(其实国企也就那12%的公积金了,并不稳定,但是稳定穷是肯定的)。 想去好一点的,建议把基础打牢,学历一定要提高(长期发展一定要,国内还是不少地方学历论的),如果有实习期建议能参与公司项目就参与,不然只会被拷打,最好从项目或者demo里把设计模式、指针、特性、模板、多线程实现并发并行、通讯协议、数据库这些基本的学会一部分,建议再学学qml和Linux,最好学一点嵌入式(Linux用在嵌入式板挺多的),掌握一门脚本语言(Python,Python,Python)和git或者svn代码管理,没签合同(不是三方),你还是校招生,校招只有一次(当然也可以说是本科一次,硕士一次,博士一次),用了错过就没有了,好多公司最喜欢招应届生了,一张白纸(又便宜又容易被PUA)。 最后,其实纠结这么多,不如第一份工作就选你最喜欢的编程语言、框架和操作系统,反正都是牛马,也不一定只吃一家喂的草
点赞 评论 收藏
分享
数开小菜鸡:你是我今早见过的最美的牛客女孩......
点赞 评论 收藏
分享
WindJerry:我三进宫也没做到 沟槽的字节 终究做不到啊
点赞 评论 收藏
分享
评论
8
1
分享

创作者周榜

更多
牛客网
牛客企业服务