写在前面

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. 基于注解的实现获取微信openId1

    最近在弄微信支付,网站有好几种不同类型的"商品",去每个支付的页面都需要获取用户的OpenId,而且获取openid要在微信的浏览器去发送请求,如果有三个不同类型的付款页面就需要写 ...

  2. Linux下删除文件名带有空格的文件

    1.使用单引号将文件名括起来进行操作: rm '2018-08-07 17-29-48.png'

  3. java的注释方法

    1.单行注释 //注释的内容 2.多行注释 /....../ 3./**......*/,这种方式和第二种方式相似.这种格式是为了便于javadoc程序自动生成文档.

  4. cmake的安装

    安装cmake有2种方式 安装方式1:源码安装 1.下载cmake源码包(https://cmake.org/download/),解压后进入解压目录 2.执行安装配置命令:配置软件二进制安装到/us ...

  5. spring*.xml配置文件明文加密

    spring*.xml配置文件明文加密 说明:客户要求spring*.xml中Oracle/Redis/MongoDB的IP.端口.用户名.密码不能明文存放,接到需求的我,很无奈,但是还是的硬着头皮搞 ...

  6. 杭电OJ1062---Text Reverse(c++)(C++库getline的使用)

    Text Reverse Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Tot ...

  7. 每日CSS_滚动页面动画效果

    每日CSS_滚动页面动画效果 2021_1_13 源码链接 1. 代码解析 1.1 html 代码片段 <section> <h2>开 始 滑 动</h2> < ...

  8. dhcp分发地址以及静态路由设置

    路由器R1配置: system-view [Huawei]sysname R1 [R1]user-interface console 0 [R1-ui-console0]idle-timeout 0 ...

  9. Maven 中 install,package,deploy命令区别

    mvn clean package依次执行了clean.resources.compile.testResources.testCompile.test.jar(打包)等7个命令. mvn clean ...

  10. 一些JavaSE学习过程中的思路整理(主观性强,持续更新中...)

    目录 一些JavaSE学习过程中的思路整理(主观性强,持续更新中...) Java书写规范 IDEA的一些常用快捷键 Java类中作为成员变量的类 Java源文件中只能有一个public类 Java中 ...