没有来源的题(似乎是什么POI?) 字符串——最小表示法

【题目描述】?
给你两个长度为 \(n\) 的字符串,问能否通过将某一字符串的一个前缀接到该串的后面使得两个字符串相等。若可以,你还可能被要求输出通过上述操作所能得到的字典序最小的字符串。
【输入格式】
? ? 第一行两个整数 \(n,T\)。
? 接下来两行,每行一个长度为 \(n\) 的字符串。

【输出格式】
? 若可以,输出 \(TAK\),否则输出 \(NIE\)。如果 \(T=1\),你还需要在下一行输出字典序最小的字符串。

【数据范围】
\(n \le 1000000\)

首先,什么是\(TAK\)?
自行百度翻译

先想想暴力做法 将一个前缀接到该串的后面就等同于是原串的一个循环移位,所以枚举所有循环移位即可。
时间复杂度\(O(n^2)\)

在这里介绍一种\(O(n)\)求出一个字符串最小的循环移位的方法
先将原串复制一遍加在原串后面 即 将\(ABCD\) 变为 \(ABCDABCD\) 这样在这个新字符串中任意取一段长为\(n\)的子串一定是原串的一种循环移位。
维护两个指针\(i, j\)和当前子串长度\(len\),表示现在正在比较从\(i\)开始的长度为\(len+1\)的子串和从\(j\)开始的长为\(len+1\)的子串。
若某一时刻,\(s[i+len] \neq s[j+len]\)
若\(s[i+len] < s[j+len]\),则说明从\(i\)开始的子串比从\(j\)开始的子串小,所以最小子串一定不会从\(j\)开始。此时可以直接让\(j = j + len + 1\),然后继续匹配。
反之让\(i = i + len + 1\)。
为什么这样可以保证正确性呢?
反证:如果此时 \(s[i+len] < s[j+len]\) ,即\(j\)被“淘汰”了,假设最小子串其实是从\(s[j+k](1 \le k \le len)\)开始的,那么一定存在从\(s[i+k]\)开始的子串会比它小。
举例:"\(ABAABBC\)": 此时\(i\)在\(s[1]\),\(j\)在\(s[4]\),\(len=2\)时发现\(s[1+2] < s[4+2]\),所以\(j\)可以直接跳到7。因为从\(S[5], S[6]\)开始的子串一定不会成为最小的。对于从\(s[5]\)开始的"\(BBC\)..."有从\(s[2]\)开始的"\(BA\)..."比它小,从\(s[6]\)开始的\(s[3]\)一定比它小。

【代码实现】

#include <bits/stdc++.h>
#define ri register int
using namespace std;

inline int read() {
    int ret = 0, flag = 1;
    char ch = getchar();
    while (ch > '9' || ch < '0') {
        if (ch == '-') flag = -1;
        ch = getchar();
    }
    while (ch <= '9' && ch >= '0') {
        ret = (ret << 1) + (ret << 3) + (ch ^ '0');
        ch = getchar();
    }
    return ret * flag;
}

int n, t;
int i, j;
int min1, min2;
char s1[2000005], s2[2000005];
bool yes = 1;

int main() {
    n = read(); t = read();
    scanf("%s", s1+1);
    scanf("%s", s2+1);
    for (ri a = 1; a <= n; a++) {
        s1[a + n] = s1[a];
        s2[a + n] = s2[a];
    }
    i = 1; j = 2;
    while (i <= n && j <= n) {
        if (i == j) j++;
        for (int len = 0; ; len++) {
            if (s1[i+len] < s1[j+len]) {
                j = j + len + 1;
                break;
            }
            if (s1[j+len] < s1[i+len]) {
                i = i + len + 1;
                break;
            }
        }
    }
    if (i <= n) min1 = i;
    else min1 = j;
    i = 1; j = 2;
    while (i <= n && j <= n) {
        if (i == j) j++;
        for (int len = 0; ; len++) {
            if (s2[i+len] < s2[j+len]) {
                j = j + len + 1;
                break;
            }
            if (s2[j+len] < s2[i+len]) {
                i = i + len + 1;
                break;
            }
        }
    }
    if (i <= n) min2 = i;
    else min2 = j;
    for (ri len = 0; len < n; len++) {
        if (s1[min1 + len] != s2[min2 + len]) {
            yes = 0;
            break;
        }
    }
    if (yes) {
        puts("TAK");
        if (t) {
            for (ri a = min1; a <= min1 + n - 1; a++) {
                putchar(s1[a]);
            }
            puts("");
        }

    } else puts("NIE");
    return 0;
} 

原文地址:https://www.cnblogs.com/ak-dream/p/AK_DREAM6.html

时间: 2024-10-13 07:58:35

没有来源的题(似乎是什么POI?) 字符串——最小表示法的相关文章

【网络流24题】餐巾计划问题(最小费用最大流)

[网络流24题]餐巾计划问题(最小费用最大流) 题面 COGS 洛谷上的数据范围更大,而且要开longlong 题解 餐巾的来源分为两种: ①新买的 ②旧的拿去洗 所以,两种情况分别建图 先考虑第一种 因为新买餐巾没有任何限制,并且随时可以买 所以直接从源点向每一天连边,容量为INF,费用为餐巾的价格 因为流要流出去,所以每个点向汇点连边,容量为每天的用量,费用为0 第二种,旧的拿去洗 首先考虑一下怎么算有多少旧的餐巾 每天用旧的餐巾的数量值一定的,不可能变多 因此从源点向这些点连边,容量为每天

编程题:用二维字符串数组实现。从键盘输入三个学生姓名,并输出。

#include<stdio.h> #include<string.h> void main() { char name[3][30]; int i; for(i=0;i<3;i++) gets(name[i]);  /*name[i]是一个一维字符数组*/ for(i=0;i<3;i++) printf("%s\n",name[i]); } 编程题:用二维字符串数组实现.从键盘输入三个学生姓名,并输出.,布布扣,bubuko.com

hdu String Problem(最小表示法入门题)

hdu 3374 String Problem 最小表示法 view code#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <string> using namespace std; const int N = 10010; int n; char s[105]; map<

leetcode_14题——Longest Common Prefix(字符串)

Longest Common Prefix Total Accepted: 44093 Total Submissions: 169565My Submissions Question Solution Write a function to find the longest common prefix string amongst an array of strings. Hide Tags String Have you met this question in a real intervi

LiberOJ 6003. 「网络流 24 题」魔术球 贪心或者最小路径覆盖

6003. 「网络流 24 题」魔术球 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 假设有 n nn 根柱子,现要按下述规则在这 n nn 根柱子中依次放入编号为 1,2,3,4,? 1, 2, 3, 4, \cdots1,2,3,4,? 的球. 每次只能在某根柱子的最上面放球. 在同一根柱子中,任何 2 22 个相邻球的编号之和为完全平方数. 试设计一个算法,计算出在 

华为上机题之输出身高差值最小的俩个人

要从5个人中选取2个人作为礼仪,其中每个人的身高范围为160-190,要求2个人的身高差值最小(如果差值相同的话,选取其中最高的两人),以升序输出两个人的身高. Smple     input:161 189 167 172 188 Sample outPut: 188 189 分析: 看到这个题,最小想到的全排问题,从5个人中抽2个人出来,一共有10中情况.计算出来后,马上想到的是用排序来这10种情况的差值,选取差值最小那一组的俩个人. 接下来想到的是用什么数据结构.每一种情况需要存储a.b两

【网络流24题】魔术球问题(最小不相交路径覆盖)

[网络流24题]魔术球问题 2014年3月7日3,5344 Description 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,4的球.(1)每次只能在某根柱子的最上面放球.(2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数.试设计一个算法,计算出在n根柱子上最多能放多少个球.例如,在4 根柱子上最多可放11 个球. 编程任务:对于给定的n,计算在n根柱子上最多能放多少个球. Input Format 文件第1 行有1个正整数n,表示柱子数. Output Fo

2017乌鲁木齐网络赛 J题 Our Journey of Dalian Ends ( 最小费用最大流 )

题目链接 题意 : 给出一副图,大连是起点,终点是西安,要求你求出从起点到终点且经过中转点上海的最小花费是多少? 分析 : 最短路是最小费用最大流的一个特例,所以有些包含中转限制或者经过点次数有限制的最短路问题都可以考虑使用最小费用最大流来建图解决. 首先对于每个点都只能经过一次这个限制,在网络流中是比较常见的一个限制,只要将所有的点由一拆二且两点间连容量为 1 且花费为 0 的边. 这题的建图很巧妙,是将中转点作为汇点,提示到了这里不如停下来想想如何建图? 然后抽象出一个超级源点,然后将起点和

lintcode 容易题:Compare Strings 比较字符串

题目: 比较字符串 比较两个字符串A和B,确定A中是否包含B中所有的字符.字符串A和B中的字符都是 大写字母 样例 给出 A = "ABCD" B = "ACD",返回 true 给出 A = "ABCD" B = "AABC", 返回 false 注意 在 A 中出现的 B 字符串里的字符不需要连续或者有序. 解题: 用数组,或者用HashMap都可以,由于char String转换成Integer不是很熟悉,搞了好久...