杭电多校第八场 Isomorphic Strings(最小表示法,循环同构)

本文主要是介绍杭电多校第八场 Isomorphic Strings(最小表示法,循环同构),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Problem Description
It is preferrable to read the pdf statment.

Two strings are called cyclical isomorphic if one can rotate one string to get another one. ‘Rotate’ here means ‘‘to take some consecutive chars (maybe none) from the beginning of a string and put them back at the end of the string in the same order’’. For example, string ‘‘abcde’’ can be rotated to string ‘‘deabc’’.

Now that you know what cyclical isomorphic is, Cuber QQ wants to give you a little test.

Here is a string s of length n. Please check if s is a concatenation of k strings, s1,s2,⋯,sk (k>1), where,

k is a divisor of n;

s1,s2,…,sk are of equal length: nk;

There exists a string t, which is cyclical isomorphic with si for all 1≤i≤k.

Print ‘‘Yes’’ if the check is positive, or ‘‘No’’ otherwise.

Input
The first line contains an integer T (1≤T≤1000), denoting the number of test cases. T cases follow.

The first line of each test case contains an integer n (1≤n≤5⋅106).

The second line contains a string s of length n consists of lowercase letters only.

It is guaranteed that the sum of n does not exceed 2⋅107.

Output
For each test case, output one line containing ‘‘Yes’’ or ‘‘No’’ (without quotes).

Sample Input
6
1
a
2
aa
3
aab
4
abba
6
abcbcc
8
aaaaaaaa

Sample Output
No
Yes
No
Yes
No
Yes

Source
2020 Multi-University Training Contest 8

题意:
将一个字符串分成k组,要求每一组都是循环同构。问是否存在这样的分法(k≥2)

思路:
k为所有字母出现次数的gcd的因数。
然后k肯定只有几百,每次再剪枝判断一下每一组的个数是否符合要求就够了。
每一组判断是否循环同构可以用最小表示法。
理论复杂度至少有4e9吧,但是因为很容易就break掉所以复杂度不会那么多,所以水过了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <iostream>
#include <map>
#include <string>
#include <set>typedef long long ll;
using namespace std;const int maxn = 5e6 + 7;int sum[maxn][30];
char s[maxn];
char sta[maxn],ed[maxn];
int b[maxn]; //每个的最小表示int mini(int n,char *tmp) {// 最小表示法int ans = 1;for (int i = 1; i <= n; i++) tmp[n+i] = tmp[i];int i = 1, j = 2, k;while (i <= n && j <= n) {for (k = 0; k < n && tmp[i+k] == tmp[j+k]; k++);if (k == n) break; // s likes "aaaaa"if (tmp[i+k] > tmp[j+k]) {i = i + k + 1;if (i == j) i++;} else {j = j + k + 1;if (i == j) j++;}}ans = min(i, j); //tmp[ans]是最小表示return ans;
}bool equal(int p1,int p2,int len) {for(int i = 1;i <= len;i++) {int x = (i + p1 - 2) % len + 1;int y = (i + p2 - 2) % len + 1;if(sta[x] != ed[y]) return false;}return true;
}bool check(int n,int k) { //分了k组if(k == 1) return false;int len = n / k;for(int i = 0;i < 26;i++) {if(sum[n][i] == 0) continue;int dat = sum[n][i] / k;for(int j = 1;j <= k;j++) {int l = (j - 1) * len + 1;int r = j * len;int num = sum[r][i] - sum[l - 1][i];if(num != dat) return false;}}for(int i = 1;i <= len;i++) {sta[i] = s[i];}b[1] = mini(len,sta);for(int i = 2;i <= k;i++) {int l = (i - 1) * len + 1;int r = i * len;for(int j = l;j <= r;j++) {ed[j - l + 1] = s[j];}b[i] = mini(len,ed);if(!equal(b[1],b[i],len)) {return false;}}return true;
}int gcd(int x,int y) {return y == 0 ? x : gcd(y,x % y);
}vector<int>DIV(int x) { //质因数分解int t = sqrt(x) + 1;vector<int>ans;for(int i = 2;i <= t;i++) {if(x % i == 0) {ans.push_back(i);if(x / i != i) {ans.push_back(x / i);}}}return ans;
}int main() {int T;scanf("%d",&T);while(T--) {int n;scanf("%d",&n);scanf("%s",s + 1);for(int i = 1;i <= n;i++) {int ch = s[i] - 'a';for(int j = 0;j < 26;j++) sum[i][j] = sum[i - 1][j];sum[i][ch]++;}int now = 0;for(int i = 0;i < 26;i++) {if(sum[n][i]) {if(!now) now = sum[n][i];else now = gcd(now,sum[n][i]);}}vector<int>div = DIV(now);div.push_back(now);int flag = 0;for(int i = 0;i < div.size();i++) {int v = div[i];if(check(n,v)) {printf("Yes\n");flag = 1;break;}}if(!flag) {printf("No\n");}}return 0;
}

这篇关于杭电多校第八场 Isomorphic Strings(最小表示法,循环同构)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/907319

相关文章

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(

Python判断for循环最后一次的6种方法

《Python判断for循环最后一次的6种方法》在Python中,通常我们不会直接判断for循环是否正在执行最后一次迭代,因为Python的for循环是基于可迭代对象的,它不知道也不关心迭代的内部状态... 目录1.使用enuhttp://www.chinasem.cnmerate()和len()来判断for

Java循环创建对象内存溢出的解决方法

《Java循环创建对象内存溢出的解决方法》在Java中,如果在循环中不当地创建大量对象而不及时释放内存,很容易导致内存溢出(OutOfMemoryError),所以本文给大家介绍了Java循环创建对象... 目录问题1. 解决方案2. 示例代码2.1 原始版本(可能导致内存溢出)2.2 修改后的版本问题在

JAVA中while循环的使用与注意事项

《JAVA中while循环的使用与注意事项》:本文主要介绍while循环在编程中的应用,包括其基本结构、语句示例、适用场景以及注意事项,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录while循环1. 什么是while循环2. while循环的语句3.while循环的适用场景以及优势4. 注意

Python中的异步:async 和 await以及操作中的事件循环、回调和异常

《Python中的异步:async和await以及操作中的事件循环、回调和异常》在现代编程中,异步操作在处理I/O密集型任务时,可以显著提高程序的性能和响应速度,Python提供了asyn... 目录引言什么是异步操作?python 中的异步编程基础async 和 await 关键字asyncio 模块理论

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

poj 1287 Networking(prim or kruscal最小生成树)

题意给你点与点间距离,求最小生成树。 注意点是,两点之间可能有不同的路,输入的时候选择最小的,和之前有道最短路WA的题目类似。 prim代码: #include<stdio.h>const int MaxN = 51;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int P;int prim(){bool vis[MaxN];

poj 2349 Arctic Network uva 10369(prim or kruscal最小生成树)

题目很麻烦,因为不熟悉最小生成树的算法调试了好久。 感觉网上的题目解释都没说得很清楚,不适合新手。自己写一个。 题意:给你点的坐标,然后两点间可以有两种方式来通信:第一种是卫星通信,第二种是无线电通信。 卫星通信:任何两个有卫星频道的点间都可以直接建立连接,与点间的距离无关; 无线电通信:两个点之间的距离不能超过D,无线电收发器的功率越大,D越大,越昂贵。 计算无线电收发器D

poj 1734 (floyd求最小环并打印路径)

题意: 求图中的一个最小环,并打印路径。 解析: ans 保存最小环长度。 一直wa,最后终于找到原因,inf开太大爆掉了。。。 虽然0x3f3f3f3f用memset好用,但是还是有局限性。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#incl