【HDU5442 2015长春网络赛F】字符串最小表示法+函数逆用循环节法+翻转串字符串哈希法

本文主要是介绍【HDU5442 2015长春网络赛F】字符串最小表示法+函数逆用循环节法+翻转串字符串哈希法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这道题有两种比较优秀的O(n)做法

前者是函数逆用循环节法,抓住了字符串最小表示法的所有性质

后者是反转字符串哈希法,使用了字符串哈希。



【HDU5442 2015长春网络赛F】字符串最小表示法+函数逆用循环节法——

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<functional>
#include<string>
#include<algorithm>
#include<time.h>
#include<bitset>
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned int UI;
typedef int Int;
template <class T> inline void gmax(T &a,T b){if(b>a)a=b;}
template <class T> inline void gmin(T &a,T b){if(b<a)a=b;}
using namespace std;
const int N=20000+10;
int casenum,casei;
int n;
char s[N];
int getmax0()
{//i是前起点,j是后起点,k是匹配长度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(t==0)k++;else{t>0?j+=k+1:i+=k+1;if(i==j)j++;k=0;}}return min(i,j);
}
int getmax1()
{//i是后起点,j是前起点,k是匹配长度int i=n-1,j=n-2,k=0;while(i>=0&&j>=0&&k<n){int t=s[(i-k+n)%n]-s[(j-k+n)%n];if(t==0)k++;else{t>0?j-=k+1:i-=k+1;if(i==j)j--;k=0;}}if(k==n){int cir=abs(i-j);return i%cir;}if(i>=0&&j>=0)return min(i,j);return i>=0?i:j;
}
int cmp(int p0,int p1)
{for(int i=0;i<n;i++){int t=s[(p0+i)%n]-s[(p1-i+n)%n];if(t>0)return 1;if(t<0)return -1;}return 0;
}
int main()
{scanf("%d",&casenum);for(casei=1;casei<=casenum;casei++){scanf("%d",&n);scanf("%s",s);int p0=getmax0();int p1=getmax1();int v=cmp(p0,p1);if(v==1)printf("%d %d\n",p0+1,0);//正着字典序大else if(v==-1)printf("%d %d\n",p1+1,1);//逆着字典序大else p0<=p1?printf("%d %d\n",p0+1,0):printf("%d %d\n",p1+1,1);//一样大看位置}return 0;
}
/*
【题意】
T(20)组数据。
对于每组数据,给你一个长度为n(2e4)的字符串,1base,即位置分别是1,2,3,4,……,n
这个字符串是环状,而且可以正着来或者反正来读。这样一共就存在2n种串,长度都为n。
我们想要知道——从哪个位置以什么方向开始读,读出的字符串的字典序是最大的。输出:
位置(1~n)和方向(0表示正着,1表示反着)输出要求:
1,如果存在多个位置,我们输出起点编号最小的位置。
2,如果从该位置正反读都可以得到最大字典序的串,那么我们正着读。【类型】
字符串最小表示法
(+字符串哈希)【分析】
这道题因为涉及到串的旋转和最大字典序。
所以一眼就想到其可以用字符串最小表示法做。
正着来的话,用字符串最小表示法就已经可以得到字典序最大的位置中编号最小的那个位置了。
不过,反着来的话,要怎么搞?
方法一:把串反转
方法二:把字符串最小表示法的模板反一下。
我们正着使用字符串最小表示法的时候,首先得到的字典序最大的串一定是编号最小的那个。
而如果倒着来,因为编号的顺序是与我们扫描的顺序相逆的。我们得到的是倒着出现的第一个。为了解决这个问题,我们有两种策略——
方法一:
既然我们现在已经得到了字典序最大的串。
那么我们用字符串哈希的方式,从1到n扫描,求出以所有位置为开头,方向是逆着来,哪个的字典序一样是最大。
方法二:
我们看到这个可能是倒着出现的第一个,而不是最后一个。
什么时候会出现多个字典序相同的串呢?
当这个串出现循环节的时候。即——最小表示法终止的条件是k==len。
这时,直接mod循环节,就可以得到第一个起点位置。【时间复杂度&&优化】
O(n)【数据】
input
9
abcabcabc
output
3 1
*/

【HDU5442 2015长春网络赛F】字符串最小表示法+翻转串字符串哈希法——

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<functional>
#include<string>
#include<algorithm>
#include<time.h>
#include<bitset>
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned int UI;
typedef int Int;
template <class T> inline void gmax(T &a,T b){if(b>a)a=b;}
template <class T> inline void gmin(T &a,T b){if(b<a)a=b;}
using namespace std;
const int N=20000+10,M=40000+10;
int casenum,casei;
int n;
char a[M];
LL u[N];
LL f[M];//f[i]表示以a[i-1]为结尾字符串的哈希前缀和
int getmax()
{//i是前起点,j是后起点,k是匹配长度int i=0,j=1,k=0;while(i<n&&j<n&&k<n){int t=a[(i+k)%n]-a[(j+k)%n];if(t==0)k++;else{t>0?j+=k+1:i+=k+1;if(i==j)j++;k=0;}}return min(i,j);
}
int cmp(int p0,int p1)
{for(int i=0;i<n;i++){int t=a[(p0+i)%n]-a[(p1-i+n)%n];if(t>0)return 1;if(t<0)return -1;}return 0;
}
int hashit(int p)
{int m=n+n;for(int i=0;i<n;i++)a[n+i]=a[i];//把字符串二倍化——扩环成链for(int i=1;i<=m;i++)f[i]=(f[i-1]*26+a[i-1]-'a')%Z;//计算字符串哈希值int V=(f[p+n]-f[p]*u[n]%Z+Z)%Z;//得到最大字典序串的哈希值for(int i=0;i<n;i++)if((f[i+n]-f[i]*u[n]%Z+Z)%Z==V)return i;//对于多个最大字典序串,返回最小的位置
}
int main()
{u[0]=1;for(int i=1;i<=20000;i++)u[i]=u[i-1]*26%Z;scanf("%d",&casenum);for(casei=1;casei<=casenum;casei++){scanf("%d",&n);scanf("%s",a);int p0=getmax();//正方向字典序最大串的最小点位strrev(a);int p1=n-1-getmax();//逆方向字典序最大串的最大点位strrev(a);p1=hashit(p1);//哈希一下就能得到逆方向字典序最大串的最小点位啦。int v=cmp(p0,p1);if(v==1)printf("%d %d\n",p0+1,0);//正着字典序大else if(v==-1)printf("%d %d\n",p1+1,1);//逆着字典序大else p0<=p1?printf("%d %d\n",p0+1,0):printf("%d %d\n",p1+1,1);//一样大看位置}return 0;
}
/*
【题意】
T(20)组数据。
对于每组数据,给你一个长度为n(2e4)的字符串,1base,即位置分别是1,2,3,4,……,n
这个字符串是环状,而且可以正着来或者反正来读。这样一共就存在2n种串,长度都为n。
我们想要知道——从哪个位置以什么方向开始读,读出的字符串的字典序是最大的。输出:
位置(1~n)和方向(0表示正着,1表示反着)输出要求:
1,如果存在多个位置,我们输出起点编号最小的位置。
2,如果从该位置正反读都可以得到最大字典序的串,那么我们正着读。【类型】
字符串最小表示法
(+字符串哈希)【分析】
这道题因为涉及到串的旋转和最大字典序。
所以一眼就想到其可以用字符串最小表示法做。
正着来的话,用字符串最小表示法就已经可以得到字典序最大的位置中编号最小的那个位置了。
不过,反着来的话,要怎么搞?
方法一:把串反转
方法二:把字符串最小表示法的模板反一下。
我们正着使用字符串最小表示法的时候,首先得到的字典序最大的串一定是编号最小的那个。
而如果倒着来,因为编号的顺序是与我们扫描的顺序相逆的。我们得到的是倒着出现的第一个。为了解决这个问题,我们有两种策略——
方法一:
既然我们现在已经得到了字典序最大的串。
那么我们用字符串哈希的方式,从1到n扫描,求出以所有位置为开头,方向是逆着来,哪个的字典序一样是最大。
方法二:
我们看到这个可能是倒着出现的第一个,而不是最后一个。
什么时候会出现多个字典序相同的串呢?
当这个串出现循环节的时候。即——最小表示法终止的条件是k==len。
这时,直接mod循环节,就可以得到第一个起点位置。【时间复杂度&&优化】
O(n)【数据】
input
9
abcabcabc
output
3 1
*/


这篇关于【HDU5442 2015长春网络赛F】字符串最小表示法+函数逆用循环节法+翻转串字符串哈希法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Java使用正则提取字符串中的内容的详细步骤

《Java使用正则提取字符串中的内容的详细步骤》:本文主要介绍Java中使用正则表达式提取字符串内容的方法,通过Pattern和Matcher类实现,涵盖编译正则、查找匹配、分组捕获、数字与邮箱提... 目录1. 基础流程2. 关键方法说明3. 常见场景示例场景1:提取所有数字场景2:提取邮箱地址4. 高级

Python中的filter() 函数的工作原理及应用技巧

《Python中的filter()函数的工作原理及应用技巧》Python的filter()函数用于筛选序列元素,返回迭代器,适合函数式编程,相比列表推导式,内存更优,尤其适用于大数据集,结合lamb... 目录前言一、基本概念基本语法二、使用方式1. 使用 lambda 函数2. 使用普通函数3. 使用 N

MySQL中REPLACE函数与语句举例详解

《MySQL中REPLACE函数与语句举例详解》在MySQL中REPLACE函数是一个用于处理字符串的强大工具,它的主要功能是替换字符串中的某些子字符串,:本文主要介绍MySQL中REPLACE函... 目录一、REPLACE()函数语法:参数说明:功能说明:示例:二、REPLACE INTO语句语法:参数

Python 字符串裁切与提取全面且实用的解决方案

《Python字符串裁切与提取全面且实用的解决方案》本文梳理了Python字符串处理方法,涵盖基础切片、split/partition分割、正则匹配及结构化数据解析(如BeautifulSoup、j... 目录python 字符串裁切与提取的完整指南 基础切片方法1. 使用切片操作符[start:end]2

python中update()函数的用法和一些例子

《python中update()函数的用法和一些例子》update()方法是字典对象的方法,用于将一个字典中的键值对更新到另一个字典中,:本文主要介绍python中update()函数的用法和一些... 目录前言用法注意事项示例示例 1: 使用另一个字典来更新示例 2: 使用可迭代对象来更新示例 3: 使用

Python开发简易网络服务器的示例详解(新手入门)

《Python开发简易网络服务器的示例详解(新手入门)》网络服务器是互联网基础设施的核心组件,它本质上是一个持续运行的程序,负责监听特定端口,本文将使用Python开发一个简单的网络服务器,感兴趣的小... 目录网络服务器基础概念python内置服务器模块1. HTTP服务器模块2. Socket服务器模块

MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)

《MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)》本文给大家介绍MyBatis的xml中字符串类型判空与非字符串类型判空处理方式,本文给大家介绍的非常详细,对大家的学习或... 目录完整 Hutool 写法版本对比优化为什么status变成Long?为什么 price 没事?怎

Go语言网络故障诊断与调试技巧

《Go语言网络故障诊断与调试技巧》在分布式系统和微服务架构的浪潮中,网络编程成为系统性能和可靠性的核心支柱,从高并发的API服务到实时通信应用,网络的稳定性直接影响用户体验,本文面向熟悉Go基本语法和... 目录1. 引言2. Go 语言网络编程的优势与特色2.1 简洁高效的标准库2.2 强大的并发模型2.

Python lambda函数(匿名函数)、参数类型与递归全解析

《Pythonlambda函数(匿名函数)、参数类型与递归全解析》本文详解Python中lambda匿名函数、灵活参数类型和递归函数三大进阶特性,分别介绍其定义、应用场景及注意事项,助力编写简洁高效... 目录一、lambda 匿名函数:简洁的单行函数1. lambda 的定义与基本用法2. lambda

Python 函数详解:从基础语法到高级使用技巧

《Python函数详解:从基础语法到高级使用技巧》本文基于实例代码,全面讲解Python函数的定义、参数传递、变量作用域及类型标注等知识点,帮助初学者快速掌握函数的使用技巧,感兴趣的朋友跟随小编一起... 目录一、函数的基本概念与作用二、函数的定义与调用1. 无参函数2. 带参函数3. 带返回值的函数4.