P5270 无论怎样神树大人都会删库跑路

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

暴力模拟都会吧......

50分代码:

#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;
}

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

抱歉,假了

康康这组数据:

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

你会发现

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

怎么办?

骂出题人

我们发现瓶颈在这:

        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)\) 的

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

答案是可以

考虑 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;
}

我们给每个数若干维随机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)\) 了

原文地址:https://www.cnblogs.com/xht37/p/10585242.html

时间: 2024-08-30 11:03:48

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

Oracle删库跑路

--10g R2 startup mount exclusive restrict; alter system enable restricted session; drop database; --11g startup mount exclusive; alter system enable restricted session; drop database; --RAC 12.1.0.2.0删库 1.先停止所有节点实例 2.在其中一节点操作,先关闭rac模式 startup nomount

又一次redis被删库跑路,索要0.6比特币

还在和媳妇儿逛街,突然同事打来电话说redis库被清空. 于是,媳妇儿说你真是乌鸦嘴,早上还说redis如何被提权的事情. 怎么刚出来就碰上了? 会不会是你搞的? 于是无形中又背锅了. 见×××姐如此着急,边安慰,边提醒让同事查一下,是什么时候发生的事情,受害面积有多大? 但是×××姐很镇静的说,不可以啊,我们ucloud云商上的redis的机器,是禁止外网登录的,所有外网的6379端口都被禁用了. 仅限本机登录,于是,我问你有加密码嘛?×××姐说,便于程序研发效率,内网环境,自然就没有加密码.

“删库跑路”这件事情真的发生了 ,还是技术总监干的!

程序员经常相互开玩笑说,大不了我们"删库跑路",这是一句玩笑话,基本上也没有人这样干,但是这两天我看到了一个新闻,真有人这样干了,还是一名技术总监. 事情的经过大概是这样子的: 邱某是某某科技公司的技术总监,2014年入职到杭州的一家科技公司,这家公司的主业业务是提供 SaaS 服务. 从2014年入职到2018年,公司的主要系统都由他搭建,包括公司的SAAS系统.API系统.电子合同的签署等服务,2018年初公司大概有4万多用户. 不知道由于什么样的原因,2018年4月,老板宓某某找

删库跑路的背后,是企业对数据安全的反思

这几天,一直在关注微盟删库事件的进展,在3月1日晚上,微盟发布最新公告称数据已经全面找回.而此时,距离事故发生的2月23日晚,过了有足足七天七夜,也就是7*24小时. 01  关于“删库跑路"的段子一直都在,而这样的真实事件也不是第一次发生了. 2018年6月,某科技公司总监因为被离职而一气之下删除了公司数据库上的一些关键索引和部分表格.虽然他事后察觉后果严重,进行了恢复,但依然给该公司造成了经济损失,被判处有期徒刑二年六个月,缓刑三年. 2018年9月,顺丰出现过一位高级工程师因手误删除了线上

程序员如何彻底地删库跑路

原文:程序员如何彻底地删库跑路 删除是删除数据最便捷的方法,如 Linux 用户最经常采用rm删除命令.实际上并没有真正的将数据从硬盘上删除,只是将文件的索引删除而已,让操作系统和使用者认为文件已经删除,又可以把腾出空间存储新的数据.数据恢复极易恢复此类不见的数据,而且也有很多专门进行数据恢复的软件. 彻底删除的原理:磁盘可以重复使用,前面的数据被后面的数据覆盖后,前面的数据被还原的可能性就大大降低了,随着被覆盖次数的增多,能够被还原的可能性就趋于 0,但相应的时间支出也就越多. 覆盖原理(ov

记一次差点删库跑路的事故

故事这样发生的,那是一个中午.... 老板:小a呀,咱测试项目部署在百度云服务器上,测试数据库部署在阿里云上,为了节省点流量,你把阿里云上的测试数据库迁移到百度云上吧. 小a : 好的,老板. 小a登陆测试服务器一看,咦?竟然有mysql的服务在跑,试着登陆了一下,密码不对,于是他仔细想了想,好像并没有任何项目用到这个数据库,这...是什么情况,难道是centos自带的吗 于是小a去问了度娘,还真的有centos自带mysql这一说,为了减少数据库版本不一致可能会导致的麻烦,小a果断卸载了原本的

史上最全mysql删库跑路必会姿势

基础篇:MySql架构与存储引擎 逻辑架构图: 连接层: mysql启动后(可以把mysql类比为一个后台的服务器),等待客户端请求,当请求到来后,mysql建立一个一个线程处理(线程池则分配一个空线程,当然也可使用nio线程模型.),每个线程独立,拥有独自内存空间.当请求为select请求则没有关系,但是请求为update时,多线程同时修改一块内存,就会引发一系列问题,由此引出 "锁"的概念. 查看mysql当前连接数: show VARIABLES like '%max_conne

删库跑路计划图鉴

原文地址:http://blog.51cto.com/14037419/2307755

当删库时如何避免跑路

延时节点解决方案 删库跑路也是个老梗了,可见在运维数据库的过程中误删除数据,或者开发的代码有bug,造成数据的误删除屡见不鲜.不过现在也有许多用于恢复或预防误删除的方案,例如SQL管理系统,将要执行的SQL先交由管理员审核,然后由管理员备份一个镜像数据库,在镜像上执行该SQL,并在执行后还原镜像.这样经过层层把关就可以大大减小出现误操作的几率. 另外,利用binlog日志也可以恢复误操作的数据,所以线上运行的数据库都会开启binlog日志功能.还有就是本小节要介绍的延时节点:在Replicati