P6739 [BalticOI 2014 Day1] Three Friends 题解
写在前面
P6739 [BalticOI 2014 Day1] Three Friends
听说这题可以用比较暴力的做法过,比如 \(string\) 里面自带的 \(substr\) ,可以看这位大佬的提交记录
模数不要用 \(49999\) ,会被卡, \(1e9+9\) 才是真爱
Solution
何为字符串哈希(可跳过):
由于字符串是具有前后关系的,可以按下述方法构造:
选取两个合适的互质常数 \(b\) 和 \(h (b < h)\), 假设有一个字符串 \(C = c_1c_2···c_m\),那么我们定义哈希函数:
\]
考虑递推实现,设 \(H(C, k)\) 为前 \(k\) 个字符构成的字符串的哈希值,则:
\]
通常,题目要求的是判断主串的一段字符与另一个匹配串是否匹配,即判断字符串 \(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\) 的哈希值是否相等,则:
\]
只要预求得 \(b^{n}\) ,就能 \(O(1)\) 判断了
可以预处理出所有 \(b^{n}\) 存在 \(Pow\) 数组里
观察目标串 \(U\) 的构造方式,发现如果 \(N\) 是偶数,一定无法构造
然后考虑枚举删除每一个字符,再将剩下的字符串均分判断哈希值是否相等
假设删去的字符在前半段,那么后半段的一定是原字符串 \(S\),如果在后半段,那么前半段一定是原字符串 \(S\) ,
所以可以分开枚举,并且预处理出对应的原字符串
那么删掉一个字符后,剩下的两段怎么合并呢?以样例字符串为例:
\]
假设枚举到 \(X\)
那么原字符串为 \(ABC\),前面要合并的两段字符串是 \(AB\),\(C\)
如果朴素计算这两个串的哈希值及原字符串哈希值,计算过程如下:
\]
\]
\]
所以不难看出 \(ABC = AB * b^{1} + C\)
对这个结论进行推广,对于字符串 \(X\),删掉其中一个字符后,分成两个字符串\(X_1,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 题解的更多相关文章
- LOJ#2632. 「BalticOI 2011 Day1」打开灯泡 Switch the Lamp On
题目描述 译自 BalticOI 2011 Day1 T3「Switch the Lamp On」有一种正方形的电路元件,在它的两组相对顶点中,有一组会用导线连接起来,另一组则不会.有 N×M 个这样 ...
- luoguP6754 [BalticOI 2013 Day1] Palindrome-Free Numbers
目录 luoguP6754 [BalticOI 2013 Day1] Palindrome-Free Numbers 简述题意: Solution: Code luoguP6754 [BalticOI ...
- P6753 [BalticOI 2013 Day1] Ball Machine
P6753 [BalticOI 2013 Day1] Ball Machine 题意 给你一个树,每次从根节点放一个求,如果其子节点有空这个球会向下滚,若有多个节点为空则找儿子中以子树内编号的最小值为 ...
- 「JOISC 2014 Day1」巴士走读
「JOISC 2014 Day1」巴士走读 将询问离线下来. 从终点出发到起点. 由于在每个点(除了终点)的时间被过来的边固定,因此如果一个点不被新的边更新,是不会发生变化的. 因此可以按照时间顺序, ...
- 「JOISC 2014 Day1」 历史研究
「JOISC 2014 Day1」 历史研究 Solution 子任务2 暴力,用\(cnt\)记录每种权值出现次数. 子任务3 这不是一个尺取吗... 然后用multiset维护当前的区间,动态加, ...
- 「题解」「JOISC 2014 Day1」历史研究
目录 题目 考场思考 思路分析及标程 题目 点这里 考场思考 大概是标准的莫队吧,离散之后来一个线段树加莫队就可以了. 时间复杂度 \(\mathcal O(n\sqrt n\log n)\) . 然 ...
- 【题解】[BalticOI 2014]friends
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3916 (BZOJ3916) 由题意可知 \(N\) 得为奇数,\(S\) 才存在,所以先特 ...
- Noip 2014酱油记+简要题解
好吧,day2T1把d默认为1也是醉了,现在只能期待数据弱然后怒卡一等线吧QAQ Day0 第一次下午出发啊真是不错,才2小时左右就到了233,在车上把sao和fate补掉就到了= = 然后到宾馆之后 ...
- 洛谷P1328==codevs3716 生活大爆炸版石头剪刀布[NOIP 2014 day1 T1]
P1328 生活大爆炸版石头剪刀布 1.8K通过 2.6K提交 题目提供者2014白永忻 标签模拟NOIp提高组2014 难度普及- 提交该题 讨论 题解 记录 最新讨论 Who can help m ...
随机推荐
- eclipse中安装Springboot的插件
1help在Eclipse Marketplace中搜索spring-tool-suite,点击install,然后接受协议,等待重启eclipse即可
- 7. JDK拍了拍你:字符串拼接一定记得用MessageFormat#format
目录 ✍前言 版本约定 ✍正文 DateFormat:日期时间格式化 SimpleDateFormat NumberFormat:数字格式化 DecimalFormat 一.0和#的使用(最常见使用场 ...
- C语言输入字符串
首先强调一点,C语言没有字符串的概念!所谓的字符串实际上还是以数组形式保存的. 方法1 -- 通过"%s"输入 优点:简单明了,输入字符只要不大于数组长度都可以. #includ ...
- jdbc-创建statement-数量过多导致游标超限
在循环中重复创建 java.sql.Connection.prepareStatement(sql) , 导致游标超限
- linux系统修改不成功无法修改密码
一.问题描述 新上架的浪潮服务器使用装机平台进行统一安装,安装完成后修改用户密码时统一无法修改,使用root账户无法修改其他用户密码,自身根密码也无法修改成功,报错如下 Changing passwo ...
- 让微信小程序开发如鱼得水
关于微信小程序开发一直想写一篇相关的文章总结和记录下,结果拖延症犯了迟迟没有下笔:这不最近天气不错,于是找一个空闲的下午将这篇文章输出下(好像跟天气没啥关系),那我们就开始吧! 注意:本文默认开发 ...
- Java 使用线程池执行若干任务
在执行一系列带有IO操作(例如下载文件),且互不相关的异步任务时,采用多线程可以很极大的提高运行效率.线程池包含了一系列的线程,并且可以管理这些线程.例如:创建线程,销毁线程等.本文将介绍如何使用Ja ...
- 微信扫码支付Native方式二以及支付回调
官方API文档https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5 1.使用jar包 1 <!--微信支付 --> 2 ...
- 【对线面试官】Java 反射&&动态代理
// 抽象类,定义泛型<T> public abstract class BaseDao<T> { public BaseDao(){ Class clazz = this.g ...
- 工具用的好,下班回家早!5分钟玩转iTerm2!
同时打开多个终端窗口,来回切换太麻烦! 能不能像IDEA一样,能够查看历史粘贴记录? 有没有办法一键登陆服务器? 工欲善其事,必先利其器!无论工作还是学习,选择好用的工具真的太重要了.今天就给大家介绍 ...