[洛谷P2444] [POI2000]病毒

洛谷题目链接:[POI2000]病毒

题目描述

二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。

示例:

例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。

任务:

请写一个程序:

1.在文本文件WIR.IN中读入病毒代码;

2.判断是否存在一个无限长的安全代码;

3.将结果输出到文件WIR.OUT中。

输入输出格式

输入格式:

在文本文件WIR.IN的第一行包括一个整数n(n≤2000)(n\le 2000)(n≤2000),表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。

输出格式:

在文本文件WIR.OUT的第一行输出一个单词:

TAK——假如存在这样的代码;

NIE——如果不存在。

输入输出样例

输入样例#1:

3
01
11
00000

输出样例#1:

NIE

题解: 显然我们是无法枚举一个无限长的串的,那么我们需要考虑找到这个构造方法.

既然是多模式串匹配,这里我们考虑使用\(AC\)自动机.

首先还是先建出\(AC\)自动机,然后我们考虑如何才能找到一个不被匹配的方法.我们知道如果匹配就是在\(AC\)自动机中访问到一个标记过的节点,或是该串的前缀中含有单词,所以我们可以在建树的过程中将有单词的点都打上标记,并且将它的所有子节点都打上标记,表示访问到这些节点就不存在合法答案.

那么如何找合法答案呢?因为在\(AC\)自动机上的匹配过程需要通过\(fail\)指针来跳转,所以如果能找到一个包含\(0\)节点(\(trie\)起始的空节点)的环,那么就可以一直在这个环上跳转一直不匹配成功,直接用\(dfs\)来找这个环就可以了.

#include<bits/stdc++.h>
using namespace std;
const int N = 3e4+5;

int n, cntn, ch[2][N], fail[N], chk[N], vis[N];
bool ok[N];
char s[N];

void insert(char *s){
    int len = strlen(s+1), now = 0;
    for(int i = 1; i <= len; i++){
        if(!ch[s[i]-'0'][now]) ch[s[i]-'0'][now] = ++cntn;
        now = ch[s[i]-'0'][now];
    }
    ok[now] = 0;
}

void build(){
    queue <int> q;
    if(ch[0][0]) q.push(ch[0][0]);
    if(ch[1][0]) q.push(ch[1][0]);
    while(!q.empty()){
        int x = q.front(); q.pop();
        for(int i = 0; i < 2; i++){
            if(ch[i][x]){
                fail[ch[i][x]] = ch[i][fail[x]];
                q.push(ch[i][x]);
                ok[ch[i][x]] &= ok[ch[i][fail[x]]];
            }
            else ch[i][x] = ch[i][fail[x]];
        }
    }
}

void dfs(int x){
    if(vis[x]) cout << "TAK" << endl, exit(0);
    if(chk[x] || !ok[x]) return;
    vis[x] = chk[x] = 1;
    dfs(ch[0][x]), dfs(ch[1][x]);
    vis[x] = 0;
}

int main(){
    cin >> n;
    memset(ok, 1, sizeof(ok));
    for(int i = 1; i <= n; i++) cin >> s+1, insert(s);
    build();
    dfs(0);
    cout << "NIE" << endl;
    return 0;
}

转载于:https://www.cnblogs.com/BCOI/p/10460224.html

2000年,POI数据下载是指在该年下载位置信息(POI)相关数据的行为。POI是指感兴趣点(Point of Interest),即地理位置上具有特殊意义或价值的地点。下载POI数据是为了获取这些特定地点的位置和相关信息,以便用于地图导航、社交媒体、市场研究等领域。 2000年,随着信息技术的快速发展,人们对位置信息的需求也日益增加。下载POI数据成为了一种常见的行为,以便更好地了解和利用周围环境。在这一年,下载POI数据的主要方式是通过互联网进行。 以2000年为例,要下载POI数据,首先需要访问相关的互联网平台或网站,如地图服务提供商、旅行网站或地理信息系统。然后,在相应的界面中,可以选择特定的地理区域、类型的POI,以及数据格式(如CSV、XML或JSON)等。接下来,点击下载按钮或链接,系统将开始传输POI数据到用户的设备上。 下载完成后,用户可以将这些POI数据导入到相应的应用程序或软件中进行进一步的分析和利用。例如,可以基于这些数据开发地图导航应用,帮助用户找到特定的商店、餐厅或景点。同时,还可以将POI数据与其他数据集结合,进行更深入的市场研究,比如确定最佳营销地点或了解消费者的行为模式。 总而言之,2000年的POI数据下载是一种通过互联网获取位置信息的行为,以满足人们对于地理位置和相关信息的需求。这一技术的发展为地图导航、社交媒体和市场研究等领域提供了更多可能性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值