4084: [Sdoi2015]双旋转字符串

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 394  Solved: 161
[Submit][Status][Discuss]

Description

给定两个字符串集合 S 和 T 。其中 S 中的所有字符串长度都恰好为 N ,而 T 中所有字符串长度都恰好为 M 。且 N+M 恰好为偶数。
如果记 S 中字符串全体为 S1,S2,...,STotalS ,而 T 中字符串全体为 T1,T2,...,TTotalT 。
现在希望知道有多少对 <i,j> ,满足将 Si 和 Tj 拼接后得到的字符串 Si+Tj 满足双旋转性。
一个长度为偶数字符串 W 可以表示成两段长度相同的字符串的拼接,即 W=U+V。如果 V 可以通过 U 旋转得到,则称 W 是满足双旋转性的。比如说字符串 U=“vijos”可以通过旋转得到“ijosv”,“josvi”,“osvij” 或“svijo”。那么“vijosjosvi”就是满足双旋转性的字符串。

Input

第一行输入四个正整数,分别为 TotalS,TotalT,N 和 M,依次表示集合 S 的大小,集合 T 的大小,集合 S 中字符串的长度和集合 T 中字符串的长度。
之后 TotalS 行,依次给出 S 中所有的字符串 Si,1≤i≤TotalS。保证每一个字符串长度都恰为 N ,且字符串只由 26 个小写字母组成。
之后 TotalT 行,依次给出 T 中所有的字符串 Ti,1≤i≤TotalT。保证每一个字符串长度都恰为 M ,且字符串只由 26 个小写字母组成。
1≤N≤100;1≤M≤100;1≤TotalS≤100;1≤Total^T≤100,2≤N*TotalS+M*TotalT≤4×10^6,N>=M

Output

输出一个整数,表示满足要求的数字对 <i,j> 有多少个。

Sample Input

4 4 7 3
vijosvi
josvivi
vijosos
ijosvsv
jos
vij
ijo
jos

Sample Output

6

HINT

Source

[Submit][Status][Discuss]



一开始题意没读好,结果做不出来。。。。

大概是要统计有多少对<i,j>使得串Si + Tj左右两半循环同构

不妨假设N >= M,反之情况类似

对于T中的每个字符串,先hash一下存在一个桶里面

暴力枚举S中的每个字符串,假设当前枚举的是Si

对于这个串,记mid = (N + M) / 2,Si的mid + 1 ~ N位在合并以后显然是给右边的半部分用的

可以在1 ~ mid位中暴力查找一下那些位置往后N - mid位与这个短串相等

每次找到一个位置,对于1 ~ mid的剩下的字符,后半部在前前半部放后显然就确定了Tj

这时候只要在桶里面查询一下这样的Tj有多少就行了


记得统计的时候不能重复,就是一类Tj对于每个Si只能用一次

用了双hash + 离散化处理这个桶,,O(|S| * logM),复杂度有点感人。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;const int maxn = 4E6 + 4;
const int mod1 = 1000000007;
const int mod2 = 99999983;
typedef long long LL;struct Hash{int h1,h2; Hash(){h1 = h2 = 0;}Hash(int h1,int h2): h1(h1),h2(h2){}Hash operator * (const Hash &B){Hash ret;ret.h1 = 1LL * h1 * B.h1 % mod1;ret.h2 = 1LL * h2 * B.h2 % mod2;return ret;}Hash operator *= (const Hash &B){h1 = 1LL * h1 * B.h1 % mod1;h2 = 1LL * h2 * B.h2 % mod2;}Hash operator += (const int &B){h1 += B; if (h1 >= mod1) h1 -= mod1;h2 += B; if (h2 >= mod2) h2 -= mod2;}Hash operator += (const Hash &B){h1 += B.h1; if (h1 >= mod1) h1 -= mod1;h2 += B.h2; if (h2 >= mod2) h2 -= mod2;}Hash operator -= (const Hash &B){h1 -= B.h1; if (h1 < 0) h1 += mod1;h2 -= B.h2; if (h2 < 0) h2 += mod2;}bool operator < (const Hash &B) const{if (h1 < B.h1) return 1;if (h1 > B.h1) return 0;return h2 < B.h2;}bool operator == (const Hash &B) const {return h1 == B.h1 && h2 == B.h2;}bool operator != (const Hash &B) const {return h1 != B.h1 || h2 != B.h2;}
}p;int n,m,ta,tb,mid,cur,Cnt;
char ch[maxn];vector <string> A,B;
vector <Hash> mi,v,h;
vector <int> cnt,vis;Hash GetHash(int L,int R)
{Hash ret; if (L > R) return ret;ret = h[R]; if (L > 0) ret -= (h[L - 1] * mi[R - L + 1]);return ret;
}void Solve1()
{int siz = n - mid; LL Ans = 0; mi.push_back(Hash(1,1));for (int i = 1; i <= n; i++) mi.push_back(mi[i - 1] * p);for (int i = 0; i < tb; i++){string &s = B[i]; Hash now;for (int j = 0; j < m; j++) now *= p,now += s[j];v.push_back(now);}sort(v.begin(),v.end()); cnt.push_back(1);for (int i = 1; i < v.size(); i++)if (v[i] == v[i - 1]) ++cnt[cur];else v[++cur] = v[i],cnt.push_back(1);while (v.size() - 1 > cur) v.pop_back();for (int i = 0; i <= cur; i++) vis.push_back(0);for (int i = 0; i < n; i++) h.push_back(Hash(0,0));for (int i = 0; i < ta; i++){string &s = A[i]; Hash now; ++Cnt;for (int j = 0; j < mid; j++) now *= p,now += s[j],h[j] = now;now = Hash(0,0);for (int j = mid; j < n; j++) now *= p,now += s[j];for (int j = 0; j <= mid - siz; j++){if (GetHash(j,j + siz - 1) != now) continue;Hash Now = GetHash(j + siz,mid - 1);Now *= mi[j]; Now += GetHash(0,j - 1);int pos = lower_bound(v.begin(),v.end(),Now) - v.begin();if (pos < v.size() && v[pos] == Now && vis[pos] != Cnt) Ans += 1LL * cnt[pos],vis[pos] = Cnt;}}cout << Ans << endl;
}void Solve2()
{int siz = m - mid; LL Ans = 0; mi.push_back(Hash(1,1));for (int i = 1; i <= m; i++) mi.push_back(mi[i - 1] * p);for (int i = 0; i < ta; i++){string &s = A[i]; Hash now;for (int j = 0; j < n; j++) now *= p,now += s[j];v.push_back(now);}sort(v.begin(),v.end()); cnt.push_back(1);for (int i = 1; i < v.size(); i++)if (v[i] == v[i - 1]) ++cnt[cur];else v[++cur] = v[i],cnt.push_back(1);while (v.size() - 1 > cur) v.pop_back();for (int i = 0; i <= cur; i++) vis.push_back(0);for (int i = 0; i < m; i++) h.push_back(Hash(0,0));for (int i = 0; i < tb; i++){string &s = B[i]; Hash now; ++Cnt;for (int j = siz; j < m; j++) now *= p,now += s[j],h[j] = now;now = Hash(0,0);for (int j = 0; j < siz; j++) now *= p,now += s[j];for (int j = siz; j <= m - siz; j++){if (GetHash(j,j + siz - 1) != now) continue;Hash Now = GetHash(j + siz,m - 1);Now *= mi[j - siz]; Now += GetHash(siz,j - 1);int pos = lower_bound(v.begin(),v.end(),Now) - v.begin();if (pos < v.size() && v[pos] == Now && vis[pos] != Cnt) Ans += 1LL * cnt[pos],vis[pos] = Cnt;}}cout << Ans << endl;
}int main()
{#ifdef DMCfreopen("DMC.txt","r",stdin);#endifp.h1 = 233; p.h2 = 131;cin >> ta >> tb >> n >> m; mid = n + m >> 1;for (int i = 0; i < ta; i++){scanf("%s",ch); string s;for (int j = 0; j < n; j++) s += ch[j];A.push_back(s);}for (int i = 0; i < tb; i++){scanf("%s",ch); string s;for (int j = 0; j < m; j++) s += ch[j];B.push_back(s);}if (n >= m) Solve1(); else Solve2();return 0;
}

4084: [Sdoi2015]双旋转字符串相关推荐

  1. 【BZOJ】4084: [Sdoi2015]双旋转字符串 哈希

    传送门:bzoj4084 题解 题面非常坑!!! 要求的是Si+TjSi+TjS_i+T_j,但实际上任意Tj+SiTj+SiT_j+S_i也可以算. AC的程序跑出的两组数据: input: 1 1 ...

  2. BZOJ 4084 [Sdoi2015]双旋转字符串

    题解:hash 至今不会unsigned long long 的输出 把B扔进map 找A[mid+1][lenA]在A[1][mid]中的位置 把A[1][mid]贴两遍(套路) 枚举A[mid+1 ...

  3. [bzoj4084][Sdoi2015]双旋转字符串_hash

    双旋转字符串 bzoj-4084 Sdoi-2015 题目大意:给定两个字符串集合 S 和 T .其中 S 中的所有字符串长度都恰好为 N ,而 T 中所有字符串长度都恰好为 M .且 N+M 恰好为 ...

  4. bzoj 4084 双旋转字符串

    给两个集合A,B,找满足要求的(a,b)的对数,可以计算对于a,哪些b成立. 还有就是字符串hash的使用,感觉平时用字符串hash太少了. 1 /************************** ...

  5. 【bzoj4084】【sdoi2015】双旋转字符串

    题解 首先题中说了$n>=m$; 分成的循环串左右两边为本质相同的单循环串循环串,分别长为$l = \frac{n + m}{2} $; 所以$S$串的前$l$位为双循环串的一半$S1$,后一半 ...

  6. 代码随想录算法训练营第八天|344.反转字符串 541. 反转字符串II 剑指Offer 05.替换空格 151.翻转字符串里的单词 剑指Offer58-II.左旋转字符串

    一.344.反转字符串 题目:编写一个函数,其作用是将输入的字符串反转过来.输入字符串以字符数组 char[] 的形式给出. 不要给另外的数组分配额外的空间,你必须原地修改输入数组.使用 O(1) 的 ...

  7. 【编程题目】左旋转字符串 ☆

    26.左旋转字符串(字符串) 题目: 定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部. 如把字符串 abcdef 左旋转 2 位得到字符串 cdefab.请实现字符串左旋转的函数. ...

  8. 经典算法面试题目-判断s2是否是s1的旋转字符串(1.8)

    题目 Assume you have a method isSubstring which checks if one word is a substring of another. Given tw ...

  9. 【剑指offer-Java版】42翻转单词顺序VS左旋转字符串

    反转单词顺序以及左旋转字符串:输入一个英文句子,翻转句子中的单词顺序,单词内部的字母顺序是不变的 – I am a student. -> student. am I 第一步,翻转句子中的所有字 ...

最新文章

  1. Android APP全面屏适配技术要点
  2. pollepoll实现分析(二)——epoll实现
  3. Js面向对象和数据类型内存分配(转)
  4. Intel Realsense D435 python wrapper pyrealsense.pipeline类
  5. php代码样式,PHP代码样式
  6. 逻辑回归和线性回归的区别_[PRML]线性分类模型贝叶斯逻辑回归
  7. 自定义linux命令工具栏,如何自定义Mac终端并使其更有用!
  8. 《推荐系统实践》样章:如何利用用户标签数据
  9. 第一季4:Hi3518E_SDK_Vx.x.x.x的SDK目录结构
  10. comparator 字符串比较大小_java – 如何使用Comparator比较空值?
  11. selenium+python谷歌驱动配置
  12. 微软TTS语音引擎实现文本朗读
  13. 蚂蚁课堂:lombok
  14. 【WordCloud】将周董的歌用词云可视化
  15. Excel快速填充列
  16. python培训抖音广告骗局
  17. ElasticSearch--Field的使用
  18. Lazada和Shopee选品分析之马来西亚电商市场详解-海鲸跨境
  19. 基于ESP8266的遥控小车
  20. 微信小程序引入原生组件——WeUI组件库,详细步骤

热门文章

  1. 猎头职场:真正城府深的人都不会做这些
  2. Pytorch 计算误判率,计算准确率,计算召回率
  3. 动画云创始人胥克谦amp;课程格子创始人李天放分享创业经历
  4. manifold 流形
  5. web接入QQ第三方登录
  6. Kvaser Memorator Professional五通道CAN/CANFD总线分析记录仪
  7. 朴素贝叶斯算法(python 实现)
  8. 爬取QQ音乐(周杰伦)
  9. 自定义彩色进度条效果
  10. 计算机科学与技术 美国 研究生 gpa3.5 托福100,历年录取数据告诉你:美国研究生申请TOEFL、GRE、GPA需要考多少分?...