【POJ】2406 Power Strings

http://poj.org/problem?id=2406

题意:给定一个字符串 L,已知这个字符串是由某个字符串 S 重复 R 次而得到的,求 R 的最大值。(长度<=1000000)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
int p[2000000];
char s[2000000];
int main() {
	while(scanf("%s", s+1), s[1]!='.') {
		int j=0, n=strlen(s+1); p[1]=0;
		for(int i=2; i<=n; ++i) {
			while(j && s[j+1]!=s[i]) j=p[j];
			if(s[j+1]==s[i]) ++j;
			p[i]=j;
		}
		if(n%(n-p[n])==0) printf("%d\n", n/(n-p[n]));
		else puts("1");
	}
	return 0;
}

kmp求出next后那么最短循环串的长度为n-next[n],只需要判断n是否整除它即可。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;

const int N=2000005;
inline void sort(int *x, int *y, int *sa, int n, int m) {
	static int c[N], i;
	for(i=0; i<m; ++i) c[i]=0;
	for(i=0; i<n; ++i) ++c[x[y[i]]];
	for(i=1; i<m; ++i) c[i]+=c[i-1];
	for(i=n-1; i>=0; --i) sa[--c[x[y[i]]]]=y[i];
}
inline void hz(int *a, int *sa, int n, int m) {
	static int t1[N], t2[N], i, j, p, *x, *y, *t;
	x=t1, y=t2;
	for(i=0; i<n; ++i) x[i]=a[i], y[i]=i;
	sort(x, y, sa, n, m);
	for(j=1, p=1; p<n; j<<=1, m=p) {
		p=0;
		for(i=n-j; i<n; ++i) y[p++]=i;
		for(i=0; i<n; ++i) if(sa[i]-j>=0) y[p++]=sa[i]-j;
		sort(x, y, sa, n, m);
		for(t=x, x=y, y=t, p=1, x[sa[0]]=0, i=1; i<n; ++i)
			x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]?p-1:p++;
	}
}
inline void geth(int *s, int *sa, int *rank, int *h, int n) {
	static int j, i, k;
	for(i=1; i<=n; ++i) rank[sa[i]]=i;
	for(k=0, i=1; i<=n; h[rank[i++]]=k)
		for(k?--k:0, j=sa[rank[i]-1]; s[i+k]==s[j+k]; ++k);
}

int a[N], sa[N], h[N], rank[N], n;
char s[N];
inline int work() {
	static int len[N], pos;
	pos=rank[1];
	for(int i=pos, mn=h[i]; i>1; --i) mn=min(h[i], mn), len[i-1]=mn;
	for(int i=pos+1, mn=h[i]; i<=n; ++i) mn=min(h[i], mn), len[i]=mn;
	int sq=sqrt(n+0.5);
	for(int k=1; k<=sq; ++k) if(n%k==0 && len[rank[k+1]]==n-k) return n/k;
	return 1;
}
int main() {
	while(scanf("%s", s+1), s[1]!='.') {
		n=strlen(s+1);
		for(int i=1; i<=n; ++i) a[i]=s[i];
		a[0]=0;
		hz(a, sa, n+1, 255);
		geth(a, sa, rank, h, n);
		printf("%d\n", work());
	}
	return 0;
}

  


 

经典题...可是我tle了......因为本题听说是用kmp.............QAQ

sa的做法就是,求出height后,我们只匹配suffix(1)和suffix(k+1)的最长公共前缀是否为n-k即可,k是枚举的长度...至于为什么,请自己想...

转载于:https://www.cnblogs.com/iwtwiioi/p/4221199.html

下载前可以先看下教程 https://pan.quark.cn/s/16a53f4bd595 小天才电话手表刷机教程 — 基础篇 我们将为您简单的介绍小天才电话手表新机型的简单刷机以及玩法,如adb工具的使用,magisk的刷入等等。 我们会确保您看完此教程后能够对Android系统有一个最基本的认识,以及能够成功通过magisk root您的手表,并安装您需要的第三方软件。 ADB Android Debug Bridge,简称,在android developer的adb文档中是这么描述它的: 是一种多功能命令行工具,可让您与设备进行通信。 该命令有助于各种设备操作,例如安装和调试应用程序。 提供对 Unix shell 的访问,您可以使用它在设备上运行各种命令。 它是一个客户端-服务器程序。 这听起来有些难以理解,因为您也没有必要去理解它,如果您对本文中的任何关键名词产生疑惑或兴趣,您都可以在搜索引擎中去搜索它,当然,我们会对其进行简单的解释:是一款在命令行中运行的,用于对Android设备进行调试的工具,并拥有比一般用户以及程序更高的权限,所以,我们可以使用它对Android设备进行最基本的调试操作。 而在小天才电话手表上启用它,您只需要这么做: - 打开拨号盘; - 输入; - 点按打开adb调试选项。 其次是电脑上的Android SDK Platform-Tools的安装,此工具是 Android SDK 的组件。 它包括与 Android 平台交互的工具,主要由和构成,如果您接触过Android开发,必然会使用到它,因为它包含在Android Studio等IDE中,当然,您可以独立下载,在下方选择对应的版本即可: - Download SDK Platform...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值