写在前面

P6739 [BalticOI 2014 Day1] Three Friends

听说这题可以用比较暴力的做法过,比如 \(string\) 里面自带的 \(substr\) ,可以看这位大佬的提交记录

模数不要用 \(49999\) ,会被卡, \(1e9+9\) 才是真爱

Solution

何为字符串哈希(可跳过):

由于字符串是具有前后关系的,可以按下述方法构造:

选取两个合适的互质常数 \(b\) 和 \(h (b < h)\), 假设有一个字符串 \(C = c_1c_2···c_m\),那么我们定义哈希函数:

\[H(C) = (c_1b^{m - 1} + c_2b^{m - 2} + ···+c_mb^{0}) \mod h
\]

考虑递推实现,设 \(H(C, k)\) 为前 \(k\) 个字符构成的字符串的哈希值,则:

\[H(C, k + 1) = H(C, k) \times b + c_{k + 1}
\]

通常,题目要求的是判断主串的一段字符与另一个匹配串是否匹配,即判断字符串 \(C = c_1c_2···c_m\) 从位置 \(k + 1\) 开始的长度为 \(n\) 的子串 \(C^{'} = c_{k + 1}c_{k + 2}···c_{k + n}\) 的哈希值与另一匹配串 \(S = s_1s_2···s_n\) 的哈希值是否相等,则:

\[H(C_{'}) = H(C, k + n) - H(C, k) \times b^{n}
\]

只要预求得 \(b^{n}\) ,就能 \(O(1)\) 判断了

可以预处理出所有 \(b^{n}\) 存在 \(Pow\) 数组里


观察目标串 \(U\) 的构造方式,发现如果 \(N\) 是偶数,一定无法构造

然后考虑枚举删除每一个字符,再将剩下的字符串均分判断哈希值是否相等

假设删去的字符在前半段,那么后半段的一定是原字符串 \(S\),如果在后半段,那么前半段一定是原字符串 \(S\) ,

所以可以分开枚举,并且预处理出对应的原字符串

那么删掉一个字符后,剩下的两段怎么合并呢?以样例字符串为例:

\[ABXCABC
\]

假设枚举到 \(X\)

那么原字符串为 \(ABC\),前面要合并的两段字符串是 \(AB\),\(C\)

如果朴素计算这两个串的哈希值及原字符串哈希值,计算过程如下:

\[AB = A * b^{1} + B * b^{0}
\]
\[C = C * b^{0}
\]
\[ABC = A * b^{2} + B * b^{1} + C * b^{0}
\]

所以不难看出 \(ABC = AB * b^{1} + C\)

对这个结论进行推广,对于字符串 \(X\),删掉其中一个字符后,分成两个字符串\(X_1,X_2\),有

\[X = X_1 * b^{len_{X_2}} + X_2
\]

根据这个公式去进行合并,然后比较两个字符串哈希值是否相同

然后这就可以了吗? 不不不

看这个样例

13
AABCABCABCABC

我们会发现删掉第一个和第二个字符都可以,但得到的原串都是 \(ABCABC\)

所以注意开个map判重即可

如果还A不了,兄弟,改个模数试试吧

Code

/*
Work by: Suzt_ilymics
Knowledge: ??
Time: O(??)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define LL long long
#define orz cout<<"lkp AK IOI!"<<endl using namespace std;
const int MAXN = 2e6+10;
const int INF = 1;
const int mod = 1e9+9;
const int b = 7; int len, cnt = 0;
char s[MAXN];
LL Pow[MAXN], Pow2, sum, H[MAXN], wz;
map<LL, LL> Map; int read(){
int s = 0, f = 0;
char ch = getchar();
while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
return f ? -s : s;
} int main()
{
len = read();
if(len % 2 == 0) {
printf("NOT POSSIBLE");
return 0;
}
cin>>(s + 1);
// for(int i = 1; i <= len; ++i) {
// cout<<s[i]<<" ";
// }
// cout<<"\n";
Pow[0] = 1;
for(int i = 1; i <= len; ++i){
Pow[i] = Pow[i - 1] * b % mod;
H[i] = (H[i - 1] * b % mod + s[i]) % mod;
}
sum = (H[len] - H[len / 2 + 1] * Pow[len / 2] % mod + mod) % mod; //后半段的哈希值
for(int i = 1; i <= len / 2 + 1; ++i){
LL pre = H[i - 1] * Pow[len / 2 + 1 - i] % mod;//删掉枚举字符后的剩余字符串的哈希值
if(Map[sum] == 0 && sum == (H[len / 2 + 1] - H[i] * Pow[len / 2 + 1 - i] % mod + pre + mod) % mod){//算出后面那一段并进行拼接
cnt++;
Map[sum]++;
wz = i;
}
}
// cout<<cnt<<"lkp\n";
sum = H[len / 2];//前半段的哈希值
for(int i = len / 2 + 2; i <= len; ++i){
LL pre = (H[i - 1] - H[len / 2] * Pow[i - len / 2 - 1] % mod + mod) % mod * Pow[len - i] % mod;//删掉枚举字符后的剩余字符串的哈希值
if(Map[sum] == 0 && sum == (H[len] - H[i] * Pow[len - i] % mod + pre + mod) % mod){//算出后面那一段并进行拼接
cnt++;
Map[sum]++;
wz = i;
}
}
// cout<<cnt<<"zsf\n";
if(cnt == 0) printf("NOT POSSIBLE");
else if(cnt == 1) {
if(wz <= len / 2) for(int i = len / 2 + 2; i <= len; ++i) cout<<s[i];
else for(int i = 1; i <= len / 2; ++i) cout<<s[i];
}
else printf("NOT UNIQUE");
return 0;
}

P6739 [BalticOI 2014 Day1] Three Friends 题解的更多相关文章

  1. LOJ#2632. 「BalticOI 2011 Day1」打开灯泡 Switch the Lamp On

    题目描述 译自 BalticOI 2011 Day1 T3「Switch the Lamp On」有一种正方形的电路元件,在它的两组相对顶点中,有一组会用导线连接起来,另一组则不会.有 N×M 个这样 ...

  2. luoguP6754 [BalticOI 2013 Day1] Palindrome-Free Numbers

    目录 luoguP6754 [BalticOI 2013 Day1] Palindrome-Free Numbers 简述题意: Solution: Code luoguP6754 [BalticOI ...

  3. P6753 [BalticOI 2013 Day1] Ball Machine

    P6753 [BalticOI 2013 Day1] Ball Machine 题意 给你一个树,每次从根节点放一个求,如果其子节点有空这个球会向下滚,若有多个节点为空则找儿子中以子树内编号的最小值为 ...

  4. 「JOISC 2014 Day1」巴士走读

    「JOISC 2014 Day1」巴士走读 将询问离线下来. 从终点出发到起点. 由于在每个点(除了终点)的时间被过来的边固定,因此如果一个点不被新的边更新,是不会发生变化的. 因此可以按照时间顺序, ...

  5. 「JOISC 2014 Day1」 历史研究

    「JOISC 2014 Day1」 历史研究 Solution 子任务2 暴力,用\(cnt\)记录每种权值出现次数. 子任务3 这不是一个尺取吗... 然后用multiset维护当前的区间,动态加, ...

  6. 「题解」「JOISC 2014 Day1」历史研究

    目录 题目 考场思考 思路分析及标程 题目 点这里 考场思考 大概是标准的莫队吧,离散之后来一个线段树加莫队就可以了. 时间复杂度 \(\mathcal O(n\sqrt n\log n)\) . 然 ...

  7. 【题解】[BalticOI 2014]friends

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3916 (BZOJ3916) 由题意可知 \(N\) 得为奇数,\(S\) 才存在,所以先特 ...

  8. Noip 2014酱油记+简要题解

    好吧,day2T1把d默认为1也是醉了,现在只能期待数据弱然后怒卡一等线吧QAQ Day0 第一次下午出发啊真是不错,才2小时左右就到了233,在车上把sao和fate补掉就到了= = 然后到宾馆之后 ...

  9. 洛谷P1328==codevs3716 生活大爆炸版石头剪刀布[NOIP 2014 day1 T1]

    P1328 生活大爆炸版石头剪刀布 1.8K通过 2.6K提交 题目提供者2014白永忻 标签模拟NOIp提高组2014 难度普及- 提交该题 讨论 题解 记录 最新讨论 Who can help m ...

随机推荐

  1. 痞子衡嵌入式:MCUXpresso IDE下SDK工程导入与workspace管理机制

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是MCUXpresso IDE下SDK工程导入与workspace管理机制. MCUXpresso IDE是恩智浦软件团队倾注很大心血研发 ...

  2. 记一次诡异的debug

    idea debug的时候会开启一个线程之行 toString,所以我们一般不要在toString 做什么操作. 目前在读spring解析自定义标签的源. 解析过程中在XmlBeanDefinitio ...

  3. mongoose连接collections会自动加s的问题解决

    问题的出现: 最近在用到mongoose连接数据库时遇到了这样的问题,我在mongoodb上创建了一个collection为course,然后在配置完mongoose连接数据库后拿到的是一个空对象. ...

  4. DML、DDL、DCL

    总体解释:DML(data manipulation language):       它们是SELECT.UPDATE.INSERT.DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据 ...

  5. .NET 云原生架构师训练营(模块二 基础巩固 MongoDB 聚合)--学习笔记

    2.5.5 MongoDB -- 聚合 排序 索引类型 创建索引 排序 // 升序 db.getCollection('author').find({}).sort({"age": ...

  6. 风炫安全WEB安全学习第十八节课 使用SQLMAP自动化注入(二)

    风炫安全WEB安全学习第十八节课 使用SQLMAP自动化注入(二) –is-dba 当前用户权限(是否为root权限) –dbs 所有数据库 –current-db 网站当前数据库 –users 所有 ...

  7. MySQL在按照某个字段分组、排序加序号

    事情是这样的,最近领导给了一个新的需求,要求在一张订单表中统计每个人第一次和第二次购买的时间间隔,最后还需要按照间隔统计计数,求出中位数等数据. 由于MySQL不想Oracle那般支持行号.中位数等, ...

  8. 【SpringMVC】SpringMVC 响应数据

    SpringMVC 响应数据 文章源码 返回值分类 返回值是字符串 Controller 方法返回字符串可以指定逻辑视图的名称,通过视图解析器解析为物理视图的地址. @Controller @Requ ...

  9. 安装weblogic 11g

    参考 https://blog.csdn.net/z69183787/article/details/38401013 https://blog.csdn.net/wjf8882300/article ...

  10. MySQL45讲:一条update语句是怎样执行的

    首先创建一张表: create table T(ID int primary key,c int); 如果要更新ID=2这行+1:应该这样写 update T set c=c+1 where ID=2 ...