【最小表示法】BZOJ1398-寻找朋友

【题目大意】

判断两个字符串是否循环同构。

【思路】

我一开始的做法是直接同时在两个字符串上求最小表示法,只有部分测试点能过,理由未知,以后再来思考。

现在做法:分别求出两个字符串的最小表示法,再比较是否相等。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int MAXN=1000000+500;
 7 char a[MAXN*2],b[MAXN*2];
 8 int n,m;
 9
10 void init()
11 {
12     scanf("%s",a);
13     scanf("%s",b);
14     n=strlen(a);
15     m=strlen(b);
16     for (int i=0;i<n;i++) a[i+n]=a[i],b[i+n]=b[i];
17 }
18
19 int getmin(char *s)
20 {
21     int i=0,j=1,k=0;
22     while (i<2*n && j<2*n && k<n)
23     {
24         int t=s[(i+k)%(2*n)]-s[(j+k)%(2*n)];
25         if (!t) k++;
26         else
27         {
28             if (t>0) i+=k+1;
29                 else j+=k+1;
30             if (i==j) j++;
31             k=0;
32         }
33     }
34     return min(i,j);
35 }
36
37 void solve()
38 {
39     int cala=getmin(a);
40     int calb=getmin(b);
41     int flag=1;
42     for (int i=0;i<n;i++)
43         if (a[(i+cala)%(2*n)]!=b[(i+calb)%(2*n)])
44         {
45             flag=0;
46             break;
47         }
48     if (flag)
49     {
50         puts("Yes");
51         for (int i=0;i<n;i++) printf("%c",a[(i+cala)%(2*n)]);
52     }
53     else puts("No");
54 }
55
56 int main()
57 {
58     init();
59     if (n==m) solve();
60         else puts("No");
61     return 0;
62 }
时间: 2024-10-06 07:36:26

【最小表示法】BZOJ1398-寻找朋友的相关文章

【BZOJ 1398】 1398: Vijos1382寻找主人 Necklace (最小表示法)

1398: Vijos1382寻找主人 Necklace Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 308  Solved: 129 Description 给定两个项链的表示,判断他们是否可能是一条项链. Input 输入文件只有两行,每行一个由0至9组成的字符串,描述一个项链的表示(保证项链的长度是相等的). Output 如果两条项链不可能同构,那么输出'No',否则的话,第一行输出一个'Yes' 第二行输出该项链的字典序最小的表示. 设

HDU 4162 Shape Number (最小表示法)

题意:给你一串n个数,求出循环来看一阶差的最小字典序:数字串看成一个顺时针的环,从某一点开始顺时针循环整个环,保证字典序最小就是答案 例如给你 2 1 3 就会得到(1-2+8 注意题意负数需要加8) (3-1) (2-3+8)-> 7 2 7 答案就是2 7 7. 典型的最小表示法.线性时间内求出最小字典序. 首先复制一遍数字串在原串后面,这样从原串任意位置开始向再后n个位置就是答案.接着双指针维护,直接双指针暴力比较数字串,当出现不同数字时,就把字典序大的那个指针向后移动尽量多的位置这样可以

【算法】字符串的最小表示法

字符串的最小表示法,就是对于一个字符串,可以将它的最后一位放到第一位来,依次类推,一共有n种变形,n为字符串长度 例如: s="00ab" 变形有(省略引号)b00a ab00 0ab0 一共4种 那么找到其中字典序最小的一个,用的算法便是这个. 定义三个指针,i,j,k 初始i=0;j=1;k=0 首先,如果s[i]<s[j]那么很明显j++ 如果s[i]>s[j]那么也很明显i=j++ 省下的就是如果s[i]==s[j]的时候. 这时候有一个性质就是在i和j之间的所有的

HDU 4162 Shape Number(字符串,最小表示法)

HDU 4162 题意: 给一个数字串(length <= 300,000),数字由0~7构成,求出一阶差分码,然后输出与该差分码循环同构的最小字典序差分码. 思路: 第一步是将差分码求出:s[i] = (s[i] - s[i+1] + 8) % 8; 第二步是求出最小字典序的循环同构差分码,我之前没注意到字符串规模..直接用set做,MLE+TLE... 正确的方式应该是一种O(n)的解法,即最小表示法.//关于最小表示法的证明与详述请参考最小表示法:) 最小表示法算法: 初始时,i=0,j=

最小表示法(模板)

最小表示法就是对于一个循环字符串,其字典序最小的状态: 显然任意一个循环串的最小表示法是唯一的,那么可以同过比较两个循环串的最小表示法来判断它们是否相同: 对于朴素算法: 初始化:i = 0, j = 1, k = 0; 若 s[i] < s[j],j++: 若 s[i] > s[j],i = j, j++: 若 s[i] == s[j],则 k++,直至 s[i + k] != s[j + k] 对于 s[i + k] < s[j + k],j++: 否则 i = j, j++: 返回

USACO 5.5.2 字符串的最小表示法

这道题是最小表示法的一个应用, 代码如下: /* ID: m1500293 LANG: C++ PROG: hidden */ #include <cstdio> #include <algorithm> #include <cstring> using namespace std; char s[100000 + 100]; int len; int mins(char s[], int len) { int i=0, j=1, k=0; while(i<len

【枚举】【最小表示法】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem F. Matrix Game

给你一个n*m的字符矩阵,将横向(或纵向)全部裂开,然后以任意顺序首尾相接,然后再从中间任意位置切开,问你能构成的字典序最大的字符串. 以横向切开为例,纵向类似. 将所有横排从大到小排序,枚举最后切开的位置在哪一横排,将这一排提到排序后的字符串数组最前面,求个"最大表示法",如果最大表示法的位置恰好在第一排的位置,那么可以用来更新答案. 如果不在第一排的位置,那么其所构成的仍然是合法的串,而且一定不会影响答案. 这是一个最小表示法的板子. #include<cstdio>

BZOJ 2176 Strange string 最小表示法

题目大意:给定一个串S,求最小表示法 n<=1000W,实在不敢写后缀自己主动机,就去学了最小表示法= = 记得用unsigned char不然WA= = 数据真是逗- - #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 10001000 using namespace std; int n; unsigned char s[

循环字符串最大最小表示法模版

循环字符串最大最小表示法模版 定义字符串abcde和cdeab同构,因为abcde转两格即为cdeab,该字符串称为循环字符串. 循环字符串的字典序最小的同构字符串称为最小表示,最大表示同理. 这里只给模版,以后再深究. int getMin(char *s) ///返回首位置 { int n=strlen(s); int i=0,j=1,k=0; while(i<n&&j<n&&k<n){ int t=s[(i+k)%n]-s[(j+k)%n]; if(