问题描述

《归妹》卦辞为:昔者恒我(姮娥)窃毋死之药于西王母,服之以(奔)月。将往,而枚占于有黄。有黄占之曰:“吉。翩翩归妹,独将西行。逢天晦芒,毋惊毋恐,后且大昌”。恒我遂托身于月,是为蟾蠩。

嫦娥去了广寒宫以后每天特别无聊,只有小兔子陪她玩。有一天,天蓬元帅来找她去东海玩,虽然她很想出去玩,可是她是后羿的妻子啊,心里又喜欢吴刚,更何况玉帝还在那盯着呢,怎么可以随随便便和他出去呢?于是她出了一道题给天蓬,答应只要他做出来了就随他一起去东海。

题目如下:

1.对于一个字符串S,定义以下n个字符串,S[i]表示一个这样的字符串:截取S的前i个字符,让截取部分的第一个字符接在剩下部分的最后一个字符后面。例:对于字符串S =“abcdef”,S[2]表示字符串“cdefab”。

2.将n个字符串进行分组,相同字符串为一组。

3.定义序列L,表示为每一组的字符串的编号按从小到大排列的序列。

4.按照L的字典序从小到大输出所有分组。

例:S =“abab”,S[0] =“abab”,S[1] =“baba”,S[2] =“abab”,S[3] =“baba”。分组L[]为(0, 2),(1, 3)。对L数组排序后:L[1]=(0, 2),L[2]=(1, 3)。因为0比1小。

这题太难了,为了成功的约到嫦娥,天蓬找到了你来帮忙,你能帮帮他吗?

输入描述

输入包含一个字符串S。

1 ≤ |S| ≤ 1000000。

S只包含小写字母。

输出描述

第一行输出一个整数K,表示分组个数。

接着K行,每行第一个整数n表示该分组有多少个字符串,后面接着n个整数,表示该分组的字符串的编号。

样例输入

ababdeadbeef

样例输出

2
2 0 2
2 1 38
1 0
1 1
1 2
1 3
1 4
1 5
1 6
1 7

这道题,我一开始直接模拟去求解,用了一个map,一个multimap和一个set来求解。遍历一遍,用set将每一次截取后重新拼接的字符串存在set容器中,同时用map计数每一个字符串出现的次数。再用multimap将每一次的截取位置保存下来。然后遍历一遍输出。(但却爆内存了 )

附错误代码(爆内存)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<algorithm>using namespace std;const int maxn = 1e6+5;
int main()
{string s;map<string, int>m;multimap<string, int>mm;set<string>S;while(cin >> s){for(int i = 0; i < s.length(); i++){string temp = s.substr(i, s.length()-i) + s.substr(0, i);S.insert(temp);m[temp]++;mm.insert(make_pair(temp, i));}map<string, int>::iterator it1;multimap<string, int>::iterator it2;cout << S.size() << endl;for(it1 = m.begin(); it1 != m.end(); it1++){cout <<(*it1).second << " ";for(it2 = mm.begin(); it2 != mm.end(); it2++){if((*it1).first == (*it2).first) cout << (*it2).second << " ";}cout << endl;}m.clear(); mm.clear(); S.clear();        }   return 0;
} 

后来看了题解才知道,原来这道题可以用KMP,找循环节来做。

首先我们可以用求解一个长度为n的字符串的next数组,从而找到字符串的循环节cir,那么该字符串就有cir组,每组有n/cir个字符。每次输出字符编号从0开始。

关于KMP的相关知识:KMP详解

ac代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>using namespace std;const int maxn = 1e6+5;
int nxt[maxn];
char str[maxn];void getNext(char str[]){int t = strlen(str);nxt[0] = -1;int j = 0;int k = -1;while(j < t){if(k == -1||str[j] == str[k]) nxt[++j] = ++k;else k = nxt[k];}
}int main()
{while(scanf("%s", str) != EOF){getNext(str);int t = strlen(str);int cir = t - nxt[t];      //循环节if(t%cir) cir = t;printf("%d\n", cir);int num = t/cir;         //有多少组for(int j = 0; j < cir; j++){printf("%d",num);for(int k = j; k < t; k += cir){printf(" %d", k);} printf("\n");}}return 0;
}

扩展KMP(求原串S1的每一个后缀子串与模式串S2的最长公共前缀长度)es[]数组去存

const int maxn=100010;   //字符串长度最大值
int next[maxn],ex[maxn]; //ex数组即为extend数组
//预处理计算next数组
void GETNEXT(char *str)
{int i=0,j,po,len=strlen(str);next[0]=len;//初始化next[0]while(str[i]==str[i+1]&&i+1<len)//计算next[1]i++;next[1]=i;po=1;//初始化po的位置for(i=2;i<len;i++){if(next[i-po]+i<next[po]+po)//第一种情况,可以直接得到next[i]的值next[i]=next[i-po];else//第二种情况,要继续匹配才能得到next[i]的值{j=next[po]+po-i;if(j<0)j=0;//如果i>po+next[po],则要从头开始匹配while(i+j<len&&str[j]==str[j+i])//计算next[i]j++;next[i]=j;po=i;//更新po的位置}}
}
//计算extend数组
void EXKMP(char *s1,char *s2)
{int i=0,j,po,len=strlen(s1),l2=strlen(s2);GETNEXT(s2);//计算子串的next数组while(s1[i]==s2[i]&&i<l2&&i<len)//计算ex[0]i++;ex[0]=i;po=0;//初始化po的位置for(i=1;i<len;i++){if(next[i-po]+i<ex[po]+po)//第一种情况,直接可以得到ex[i]的值ex[i]=next[i-po];else//第二种情况,要继续匹配才能得到ex[i]的值{j=ex[po]+po-i;if(j<0)j=0;//如果i>ex[po]+po则要从头开始匹配while(i+j<len&&j<l2&&s1[j+i]==s2[j])//计算ex[i]j++;ex[i]=j;po=i;//更新po的位置}}
}

嫦娥奔月(KMP,找循环节)及其扩展KMP相关推荐

  1. HDU - 6153 A Secret(KMP的next数组性质/扩展KMP)

    题目链接:点击查看 题目大意:给出两个字符串a和b,我们首先定义L:字符串b当前的后缀子字符串长度,N:字符串b当前的后缀在字符串a中出现的次数,现在询问,对于字符串b的每一个后缀,求出L*N之和,答 ...

  2. MUV LUV EXTRA -( kmp最小循环节 )

    题目链接:点击进入 题意 一个无限循环小数( 从小数点后 某一位 开始依次不断地重复出现前一个或一节数字的十进制无限小数,叫做循环小数 ),真实价值 = a * p - b * l ( a , b 是 ...

  3. hdu_1358Period(kmp找循环前缀)

    题目在这儿 Period Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Tot ...

  4. 【POJ - 1961】Period(KMP,循环节问题)

    题干: For each prefix of a given string S with N characters (each character has an ASCII code between ...

  5. hdu 3746 kmp求循环节 下标从1开始

    长度为m[1,2...m]的模式的循环节为 m-next[m] , aaa  循环节clc为1  (clc=m-next[m]= 3-2  =1)       此时   m%clc == 0   表示 ...

  6. ( KMP 求循环节的个数)Power Strings -- poj -- 2406

    链接: http://poj.org/problem?id=2406 Power Strings Time Limit:3000MS     Memory Limit:65536KB     64bi ...

  7. KMP、扩展KMP、MANACHER

    一.KMP 作用:用于在一个文本串S内查找一个模式串P出现的位置 string str = "bacbababadababacambabacaddababacasdsd"; str ...

  8. hdu4291 暴力循环节+矩阵快速幂

    题意:       给你一个关系式,x[n] = 3*x[n-1] + x[n-2],求x(x(x[n]))%1000000007. 思路:       做这个题目要明确一点,就是对于取余操作大多数时 ...

  9. HDU - 6629 string matching(扩展KMP)

    题目链接:点击查看 题目大意:给出一个字符串 s 和一个暴力程序,用于求解 s 的每个后缀和原字符串的最长公共前缀,现在问一共需要执行多少次比较操作 题目分析:首先肯定不能暴力去模拟,时间复杂度n*n ...

最新文章

  1. tableau应用实战案例(三)-如何用Tableau制作网络关系图
  2. xcode快速开发 代码块
  3. Dll学习一_Dll 创建并动态引用窗体且释放窗体Demo
  4. 【文章】你和自己聊过吗?你很重要
  5. tsung压测mysql_高并发测试工具Tsung使用教程
  6. scikit-image 库简介
  7. ubuntu12.04升级svn到 1.7
  8. sql server 2000数据库 最近经常出现某进程一直占用资源,阻塞?死锁?
  9. 如何写好一份专利交底书?
  10. STM32-雨滴传感器
  11. 今日头条小程序是什么
  12. Photoshop是什么?
  13. 解决ios的webview中上/下拉露出黑灰色背景问题
  14. 有机酸膜分离之柠檬酸生产应用反渗透技术
  15. Unity SteamVR锁定头盔位置旋转
  16. 第九章:项目资源管理-0316
  17. 解决ios下的微信页面背景音乐无法自动播放问题
  18. 泰勒公式浅谈原理(转)
  19. (SIP-1-话机注册)关于IP话机通过SIP协议注册到PBX电话交换机的全过程解析-如何看wireshark中的报文
  20. 线性代数(十六) : 矩阵的左零空间及四个基本子空间总结

热门文章

  1. 苹果xsmax怎么开机_苹果XSMAX进水不开机维修
  2. 联想研发支出从未超过2% 被指还不如政府补贴多
  3. C语言指针(个人的认识)
  4. 我去,JS自执行匿名函数竟然有20几种写法!
  5. 《IT项目管理》读书笔记(9) —— 项目沟通管理
  6. Lotus Notes应用经验谈
  7. Python LDA主题模型实战
  8. python实现双向最大匹配法
  9. OpenMPI 安装
  10. 【Python-ML】神经网络激励函数-Softmax