题目地址:P5270 无论怎样神树大人都会删库跑路

第一眼看上去是模拟,似乎是 \(O(n)\) 的

水题

信心满满的写完:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 6;
int n, T, Q, m, c[N], r[N], mx, cnt, d[N], ans, s[N], now;
vector<int> e[N];
queue<int> q;

int main() {
    cin >> n >> T >> Q;
    for (int i = 1; i <= T; i++) {
        int x;
        scanf("%d", &x);
        mx = max(mx, x);
        ++c[x];
    }
    for (int i = 1; i <= n; i++) {
        int len;
        scanf("%d", &len);
        while (len--) {
            int x;
            scanf("%d", &x);
            mx = max(mx, x);
            e[i].push_back(x);
        }
    }
    cin >> m;
    for (int i = 1; i <= m; i++) scanf("%d", &r[i]);
    for (int x = 0; x <= mx; x++) if (c[x] == d[x]) ++cnt;
    for (int i = 1; i <= m && i <= Q; i++) {
        for (unsigned int j = 0; j < e[r[i]].size(); j++) {
            int x = e[r[i]][j];
            q.push(x);
            if (d[x] == c[x]) --cnt;
            ++d[x];
            if (d[x] == c[x]) ++cnt;
        }
        while ((int)q.size() > T) {
            int x = q.front();
            q.pop();
            if (d[x] == c[x]) --cnt;
            --d[x];
            if (d[x] == c[x]) ++cnt;
        }
        if (cnt == mx + 1) ++ans;
    }
    if (Q <= m) {
        cout << ans << endl;
        return 0;
    }
    Q -= m;
    for (int i = 1; i <= m; i++) {
        for (unsigned int j = 0; j < e[r[i]].size(); j++) {
            int x = e[r[i]][j];
            q.push(x);
            if (d[x] == c[x]) --cnt;
            ++d[x];
            if (d[x] == c[x]) ++cnt;
        }
        while ((int)q.size() > T) {
            int x = q.front();
            q.pop();
            if (d[x] == c[x]) --cnt;
            --d[x];
            if (d[x] == c[x]) ++cnt;
        }
        if (cnt == mx + 1) ++now;
        s[i] = now;
    }
    cout << ans + now * (Q / m) + s[Q%m] << endl;
    return 0;
}

Wait!

Q:为什么在模拟完第一遍后要再模拟一遍呢?

A:第一遍初始时没有数,而后面会有剩下的数留到下一轮,因此第一遍对 \(ans\) 的贡献要特判QAQ

一遍AC

然而......

模拟是 \(O(n)\) 的?

抱歉,假了,50分滚粗

康康这组数据:

1 1e5 1e9
1 1 ... 1
1e5 1 1 ... 1
1e5
1 1 ... 1

你会发现

被卡成 \(O(n^2)\) 了!

Q:怎么办?

A:骂毒瘤出题人

我们发现瓶颈在这:

        for (unsigned int j = 0; j < e[r[i]].size(); j++) {
            int x = e[r[i]][j];
            q.push(x);
            if (d[x] == c[x]) --cnt;
            ++d[x];
            if (d[x] == c[x]) ++cnt;
        }
        while ((int)q.size() > T) {
            int x = q.front();
            q.pop();
            if (d[x] == c[x]) --cnt;
            --d[x];
            if (d[x] == c[x]) ++cnt;
        }

这个插入删除是 \(O(n)\) 的!

Q:我们能不能把它搞成 \(O(1)\) 的?

A:可以

考虑 Hash 思想

先看代码:

#include <bits/stdc++.h>
#define ull unsigned long long
#define pii pair<int, int>
using namespace std;
const int N = 1e5 + 6;
int n, T, Q, S[N], R[N], m, mx, len, ans, s[N], kkk;
vector<int> e[N];
struct H {
    ull h[6];
    H() {
        memset(h, 0, sizeof(h));
    }
} Hash[N], numS, now;
vector<H> num[N];
deque<pii> q;

inline ull RA() {
    return (ull)rand() * rand() * rand() * rand() * rand() * rand();
}

inline void add(H &a, H &b) {
    for (int i = 0; i < 6; i++) a.h[i] += b.h[i];
}

inline void del(H &a, H &b) {
    for (int i = 0; i < 6; i++) a.h[i] -= b.h[i];
}

inline bool equ(H a, H b) {
    for (int i = 0; i < 6; i++)
        if (a.h[i] != b.h[i]) return 0;
    return 1;
}

int main() {
    srand((unsigned)time(0));
    cin >> n >> T >> Q;
    for (int i = 1; i <= T; i++) {
        scanf("%d", &S[i]);
        mx = max(mx, S[i]);
    }
    for (int i = 1; i <= n; i++) {
        int len;
        scanf("%d", &len);
        while (len--) {
            int x;
            scanf("%d", &x);
            mx = max(mx, x);
            e[i].push_back(x);
        }
    }
    cin >> m;
    for (int i = 1; i <= m; i++) scanf("%d", &R[i]);
    for (int i = 0; i <= mx; i++)
        for (int j = 0; j < 6; j++)
            Hash[i].h[j] = RA();
    for (int i = 1; i <= T; i++) add(numS, Hash[S[i]]);
    for (int i = 1; i <= n; i++) {
        int len = e[i].size();
        num[i].resize(len);
        for (int j = len - 1; ~j; j--)
            add(num[i][j], Hash[e[i][j]]);
        for (int j = len - 2; ~j; j--)
            add(num[i][j], num[i][j+1]);
    }
    for (int i = 1; i <= m && i <= Q; i++) {
        add(now, num[R[i]][0]);
        len += e[R[i]].size();
        q.push_back({R[i], 0});
        while (len > T) {
            pii x = q.front();
            q.pop_front();
            del(now, num[x.first][x.second]);
            len -= e[x.first].size() - x.second;
            if (len < T) {
                int k = num[x.first].size() - (T - len);
                q.push_front({x.first, k});
                add(now, num[x.first][k]);
                len = T;
            }
        }
        if (equ(now, numS)) ++ans;
    }
    if (Q <= m) {
        cout << ans << endl;
        return 0;
    }
    Q -= m;
    for (int i = 1; i <= m && i <= Q; i++) {
        add(now, num[R[i]][0]);
        len += e[R[i]].size();
        q.push_back({R[i], 0});
        while (len > T) {
            pii x = q.front();
            q.pop_front();
            del(now, num[x.first][x.second]);
            len -= e[x.first].size() - x.second;
            if (len < T) {
                int k = num[x.first].size() - (T - len);
                q.push_front({x.first, k});
                add(now, num[x.first][k]);
                len = T;
            }
        }
        if (equ(now, numS)) ++kkk;
        s[i] = kkk;
    }
    cout << ans + kkk * (Q / m) + s[Q%m] << endl;
    return 0;
}

(小声)不好意思kkk,窝真的是没有变量名可用才用您的QWQ

我们给每个数若干维随机 Hash

    for (int i = 0; i <= mx; i++)
        for (int j = 0; j < 6; j++)
            Hash[i].h[j] = RA();

一串数的 Hash 值定义为每个数的每一维 Hash 分别相加(unsigned long long自然溢出)

如果两个串任意排列后可以相同,这两个串对应的每一维都应该相同

那么插入和删除就都可以做到 \(O(1)\) 了

你卡我随机化鸭

你卡我 Hash 鸭

你卡我常数大鸭

P5270 无论怎样神树大人都会删库跑路的更多相关文章

  1. Mysql binlog备份数据及恢复数据,学会这个,我在也不怕删库跑路啦~

    导读 我一直都主张,技多不压身(没有学不会的技术,只有不学习的人),多学一项技能,未来就少求人一次.网上经常听到xxx删库跑路,万一真的遇到了,相信通过今天的学习,也能将数据再恢复回来~~~ 当然啦, ...

  2. Oracle删库跑路

    --10g R2 startup mount exclusive restrict; alter system enable restricted session; drop database; -- ...

  3. SQL 从入门到 DBA 删库跑路

    SQL 从入门到 DBA 删库跑路 一.基础 人员信息表: ID 姓名 性别 出生 婚否 学历 工资 工会 35009449 孙xx 男 1978-2-17 未婚 中专 3000 TRUE 35000 ...

  4. 数据误操作,删库跑路?教你使用ApexSQLLog工具从 SQLServer日志恢复数据!

    前几天同事不小心误操作,将SQLServer库的一张表的一个状态字段给刷成了一个统一状态,由于是update执行所以原来的相关状态无法确定.发生这种事情的时候我的小伙伴背后 一凉,估计心里里面想这怕是 ...

  5. 教你如何6秒钟往MySQL插入100万条数据!然后删库跑路!

    教你如何6秒钟往MySQL插入100万条数据!然后删库跑路! 由于我用的mysql 8版本,所以增加了Timezone,然后就可以了 前提是要自己建好库和表. 数据库test, 表user, 三个字段 ...

  6. 【巨杉数据库SequoiaDB】巨杉Tech | “删库跑路”又出现,如何防范数据安全风险?

    最近,又双叕有企业被“删库”了.来自微盟官网的消息,微盟的业务系统数据库(包括主备)遭遇其公司运维人员的删除,系统将停止运营超48小时. 频发的类似事件也让大家对于数据安全的关注不断提高.数据是一个科 ...

  7. The Data Way Vol.3|做到最后只能删库跑路?DBA 能做的还有很多

    关于「The Data Way」 「The Data Way」是由 SphereEx 公司出品的一档播客节目.这里有开源.数据.技术的故事,同时我们关注开发者的工作日常,也讨论开发者的生活日常:我们聚 ...

  8. 因为它,我差点删库跑路:js防抖与节流

    前言 前端踩雷:短时间内重复提交导致数据重复. 对于前端大佬来说,防抖和节流的技术应用都是基本操作.对于"兼职"前端开发的来说,这些都是需要躺平的坑. 我们今天就来盘一盘js防抖与 ...

  9. 大数据开发从入门小白到删库跑路(一)- 获取Hadoop

    Hadoop是一个可以通过相对简单编程模型实现跨多台计算机集群分布式处理大型数据集的框架.它不是依赖于高额成本的硬件可靠性来提供高可用性,Hadoop的设计能从单个服务器扩展到数千台机器,每个机器提供 ...

随机推荐

  1. python自动化开发-[第十三天]-前端Css续

    今日概要: 1.伪类选择器 2.选择器优先级 3.vertical-align属性 4.backgroud属性 5.边框border属性 6.display属性 7.padding,margine(见 ...

  2. libmysqlclient.so.18: cannot open shared object file

    libmysqlclient.so.18: cannot open shared object file 解决libmysqlclient.so.18: cannot open shared obje ...

  3. ADC触摸屏

    目录 ADC触摸屏 硬件原理 等效电路 测量逻辑 程序设计(一)获得ADC 寄存器初始化 中断初始化 ADC模式(中断.测量) 中断函数 程序设计(二)获得坐标 生产者与消费者 ADC获取 程序优化 ...

  4. 网络编程基础【day09】:socket解决粘包问题之MD5(八)

    本节内容 1.概述 2.代码实现 一.概述 上一篇博客讲到的用MD5来校验还是用的之前解决粘包的方法,就是客户端发送一个请求,等待服务端的确认的这样的一个笨方法.下面我们用另外一种方法:就是客户端已经 ...

  5. SpringBoot笔记十二:缓存

    目录 非缓存项目 缓存 JSR-107 Spring缓存抽象 @Cacheable @CachePut @CacheEvict @Caching @CacheConfig 整合Redis 先在Dock ...

  6. python dom操作

    1.DOM介绍 (1)什么是DOM DOM:文档对象模型.DOM 为文档提供了结构化表示,并定义了如何通过脚本来访问文档结构.目的其实就是为了能让js操作html元素而制定的一个规范. DOM就是由节 ...

  7. WebAPI性能优化之压缩解压

    有时候为了提升WebAPI的性能,减少响应时间,我们会使用压缩和解压,而现在大多数客户端浏览器都提供了内置的解压支持.在WebAPI请求的资源越大时,使用压缩对性能提升的效果越明显,而当请求的资源很小 ...

  8. Linux 内核源代码根目录

    1.    arch :与体系结构相关的文件 2.    block: 包含块存储设备IO调度算法的实现 3.    cryrto: 密码操作有关 4.    Documention: 内核中各个子系 ...

  9. MVC Repository模式

    近来发现很多ASP.NET MVC的例子中都使用了Repository模式,比如Oxite,ScottGu最近发布的免费的ASP.NET MVC教程都使用了该模式.就简单看了下. 在<企业架构模 ...

  10. GIL 全局解释器

    全局解释器锁 GIL 相当于给python解释器加了一把互斥锁 每一个进程都有一把互斥锁,所有线程必须先拿到解释器,才能执行代码, 同一进程下,所有线程并发 在 Cpython 解释器下,多个进程可以 ...