BZOJ 3574 HNOI 2014 抄卡组 字符串Hash+STL

题目大意:给出一些表示卡组的字符串,字符串中可能出现‘*’符号(并不是BZ上以前写的‘#’号,更不是“ ‘*’ ”。。。),这个符号可以代表任意字符串(包括空串)。问所有的字符串是否能够相同。

思路:题目描述,样例有误,数据范围坑爹,官方数据出错,BZ输入流过大RE。。这题做完了都不知道该说什么好了。。。

整个就是一个常数很大的O(n)模拟题而已。。。

首先数据范围十分坑爹,N*最长字符串长度<=2*10^8,你这让我怎么开数组?好吧,那就全篇vector

先弄出所有字符串的Hash值,之后分三种情况讨论:

1.所有的字符串中都不含通配符。这种情况很简单,只要比较所有字符串的Hash值就行了。

2.所有字符串都含有通配符。注意到通配符可以代替任意字符串,那我们不管中间的通配符了,只需要看前缀和后缀。前缀是从开头到第一个通配符,后缀同理。按照前缀从短到长排序,然后逐个判断前缀是否相等,后缀同理。中间的通配符肯定能自己搞成一样的。

3.有的字符串中含有通配符,有的字符串中不含有通配符。先把不含有通配符的字符串比较一下,然后就是让所有含有通配符的字符串变成不含有通配符的字符串那样就行了。按照上一种情况的想法,先把前缀和后缀去掉,然后让含有通配符的那个的中间部分匹配上不含有通配符的中间部分的字符串。直接暴力就行了,反正怎么弄都是O(n)。利用通配符分割含有通配符的中间部分,然后用一个指针去不含有通配符的字符串中扫。

注意各种边界讨论;此外不能使用cin,cout等流,可能导致流过大而RE(我会说因为这个破事调了一个点?谁向BZ反映一下啊。。。

但是用了大量的STL不用cin怎么搞?可行的方法是关闭流的同步(详情见代码)。至于为什么可行,谜。

CODE:

#include <vector>
#include <string>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 100010
#define BASE 2333
using namespace std;

unsigned long long power[10000010];
bool flag;

struct Complex{
    int wildcard,length;
    vector<unsigned long long> hash;
    vector<int> card;

    bool operator <(const Complex &a)const {
        return flag ? card[1] < a.card[1]:length - card[wildcard] < a.length - a.card[a.wildcard];
    }
    void Reset() {
        wildcard = length = 0;
        hash.clear();
        hash.push_back(0);
        card.clear();
        card.push_back(0);
    }
    void GetHash(string s) {
        for(string::iterator it = s.begin(); it != s.end(); ++it) {
            hash.push_back(hash.back() * BASE + *it);
            ++length;
            if(*it == '*') {
                ++wildcard;
                card.push_back(length);
            }
        }
    }
    unsigned long long GetHash(int l,int r)const {
        return hash[r] - hash[l - 1] * power[r - l + 1];
    }
    bool Pair(const Complex &p) {
        int suffix_len = length - card[wildcard];
        if(p.length < suffix_len + card[1] - 1)  return false;
        if(GetHash(1,card[1] - 1) != p.GetHash(1,card[1] - 1))  return false;
        if(GetHash(card[wildcard] + 1,length) != p.GetHash(p.length - suffix_len + 1,p.length)) return false;
        int st = card[1],ed = p.length - suffix_len;
        for(int i = 1; i < wildcard; ++i) {
            int len = card[i + 1] - card[i] - 1;
            unsigned long long h = GetHash(card[i] + 1,card[i + 1] - 1);
            while(1) {
                if(st + len - 1 > ed)    return false;
                if(p.GetHash(st,st + len - 1) == h) {
                    st += len;
                    break;
                }
                ++st;
            }
        }
        return true;
    }
}src[MAX];

int T,cnt;
string temp;

void Pretreatment()
{
    power[0] = 1;
    for(int i = 1; i <= 10000000; ++i)
        power[i] = power[i - 1] * BASE;
}

inline void Initialize()
{
    for(int i = 1; i <= cnt; ++i)
        src[i].Reset();
}

inline bool Judge()
{
    unsigned long long no_card = 0;
    int p = 0;
    for(int i = 1; i <= cnt; ++i)
        if(!src[i].wildcard) {
            if(!p)
                no_card = src[i].hash[src[i].length],p = i;
            else
                if(no_card != src[i].hash[src[i].length])
                    return false;
        }
    if(p) {
        for(int i = 1; i <= cnt; ++i)
            if(src[i].wildcard)
                if(!src[i].Pair(src[p]))
                    return false;
    }
    else {
        flag = true;
        sort(src + 1,src + cnt + 1);
        for(int i = 1; i < cnt; ++i)
            if(src[i].GetHash(1,src[i].card[1] - 1) != src[i + 1].GetHash(1,src[i].card[1] - 1))
                return false;
        flag = false;
        sort(src + 1,src + cnt + 1);
        for(int i = 1; i < cnt; ++i) {
            int suffix_len = src[i].length - src[i].card[src[i].wildcard];
            if(src[i].GetHash(src[i].card[src[i].wildcard] + 1,src[i].length) != src[i + 1].GetHash(src[i + 1].length - suffix_len + 1,src[i + 1].length))
                return false;
        }
    }
    return true;
}

int main()
{
    ios::sync_with_stdio(false);
    Pretreatment();
    for(cin >> T; T--;) {
        cin >> cnt;
        Initialize();
        for(int i = 1; i <= cnt; ++i) {
            cin >> temp;
            src[i].GetHash(temp);
        }
        puts(Judge() ? "Y":"N");
    }
    return 0;
}

时间: 2024-10-12 16:24:11

BZOJ 3574 HNOI 2014 抄卡组 字符串Hash+STL的相关文章

HNOI 2014

D1T1:画框 frame 题意:给你两个n阶正整数方阵,请你求最大的\( \sum_{i = 1}^{n} A_{i, p_i}\times \sum_{i = 1}^{n} B_{i, p_i}  \)其中\({p_i}\)是一个n的排列.\(n \le 70\). 如果A=B,这就是一个二分图最大完美匹配问题,那么我们可以用费用流或者KM算法解决,然而A却可以不等于B,我们需要另辟蹊径. 当年我看到这道题就只会随机化乱搞,现在看来,如果仔细的思考还是可以搞出来的. 想到,我们可以求出对于A

2014.8.20break,continue,字符串,数字和日期

(一)break与continue break——彻底终断循环 continue——中断本次循环,继续下次循环 break举例: 1 //求100以内所有质数 2 for (int i = 1; i <= 100; i++) 3 { 4 int n = 0;//n用来存放能被整除的数的个数 5 for (int j = 1; j <= i; j++) 6 { 7 if (i % j == 0) 8 { 9 n++; 10 } 11 if (n > 2) 12 { 13 break;//跳

java练习题:现给出二组字符串,比较他们看是否相等

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringTokenizer; /** * 假设字符串类似这样的aba和aab就相等,现在随便给你二组字符串,请编程比较他们看是否相等 * */public class EqualDemo { public static void main(String[] args) { //先读

2014牡丹江网络预选赛I题(字符串hash+简单DP)zoj3817

Chinese Knot Time Limit: 2 Seconds      Memory Limit: 65536 KB      Special Judge Chinese knot is a decorative handicraft that began as a form of Chinese folk artifact in the Tang and Song Dynasty in China. It was later popularized in the Ming. Alice

转载:字符串hash总结(hash是一门优雅的暴力!)

转载自:远航休息栈 字符串Hash总结 Hash是什么意思呢?某度翻译告诉我们: hash 英[hæ?] 美[hæ?]n. 剁碎的食物; #号; 蔬菜肉丁;vt. 把…弄乱; 切碎; 反复推敲; 搞糟; 我觉得Hash是引申出 把...弄乱 的意思. 今天就来谈谈Hash的一种——字符串hash. 据我的理解,Hash就是一个像函数一样的东西,你放进去一个值,它给你输出来一个值.输出的值就是Hash值.一般Hash值会比原来的值更好储存(更小)或比较. 那字符串Hash就非常好理解了.就是把字符

字符串Hash总结(转载)

转载地址 Hash是什么意思呢?某度翻译告诉我们: hash 英[hæ?] 美[hæ?] n. 剁碎的食物; #号; 蔬菜肉丁; vt. 把…弄乱; 切碎; 反复推敲; 搞糟; 我觉得Hash是引申出 把...弄乱 的意思. 今天就来谈谈Hash的一种——字符串hash. 据我的理解,Hash就是一个像函数一样的东西,你放进去一个值,它给你输出来一个值.输出的值就是Hash值.一般Hash值会比原来的值更好储存(更小)或比较. 那字符串Hash就非常好理解了.就是把字符串转换成一个整数的函数.而

[知识点] 字符串Hash

1.前言 字符串的几大主要算法都多少提及过,现在来讲讲一个称不上什么算法, 但是非常常用的东西——字符串Hash. 2.Hash的概念 Hash更详细的概念不多说了,它的作用在于能够对复杂的状态进行简单的表达,更方便的用于判重.在搜索的时候,或是动规的时候,都有过类似的做法.在实际应用中,也是非常重要的,这也就是为什么存在什么暴雪公司的Hash算法等等:加密环节也是Hash的重要之处,MD5码就是一个经典的例子. 字符串Hash的方式多式多样,重点来解释一下最简单的,最常用的. 3.BKDRHa

hdu 1880 魔咒词典(字符串hash)

题目链接:hdu 1880 魔咒词典 题意: 给你一个10w的词典,让你输出对应的字段. 题解: map暴力存字符串肯定会卡内存,这里用BKDR字符串hash一下,用map映射一下. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 typedef unsigned long long ull; 5 6 const int N=1e5+7,seed=133

字符串hash + 二分答案 - 求最长公共子串 --- poj 2774

Long Long Message Problem's Link:http://poj.org/problem?id=2774 Mean: 求两个字符串的最长公共子串的长度. analyse: 前面在学习后缀数组的时候已经做过一遍了,但是现在主攻字符串hash,再用字符串hash写一遍. 这题的思路是这样的: 1)取较短的串的长度作为high,然后二分答案(每次判断长度为mid=(low+high)>>1是否存在,如果存在就增加下界:不存在就缩小上界): 2)主要是对答案的判断(judge函数