Problem 1564 - A - Circle
Problem's Link: http://acm.whu.edu.cn/land/problem/detail?problem_id=1564
Mean:
给你一个长度不超过1e6的数字串,求第k大的环状数字串的前面那个位置。
analyse:
好吧,我承认这是个水题,比赛的时候sb了,因为原来做过后缀自动机求解字符串的环状最小表示法,所以一直用后缀自动机的知识去套k小表示法,比赛的时候太固执了。
这题就是后缀数组的sa[]数组的运用,sa[i]=k表示的是字符串所有的后缀按字典序排序后,第i个后缀排在第k个。
那么我们只需将数字串复制一遍接在原串后面(环状),对s求一遍后缀数字得到sa数组,然后找到sa<=n的第k个sa,那么sa[i]-1就是答案。
为什么?看这张图:
连接后的字符串我们可以得到2*n个字符串,但是我们只需关心前n个字符串就可,因为后面的n个字符串其实根本没作用,他们只相当于前n个字符串的前缀的重复出现而已。
所以我们只需要找到满足sa[i]<=n的第k个就行,sa[i]-1就是答案。
Time complexity: O(n)
Source code:
// Memory Time// 1347K 0MS// by : crazyacking// 2015-04-20-19.00#include
#include#include #include #define MAXN 1000010using namespace std;int n,k,len,si,now;char s[MAXN];vector num;int GetAns(vector tp,int tk,int l){ if(tp.size()==1 || l==n-1) return tp[0]; vector cnt[10]; si=tp.size(); for(int i=0;i cnt[now].size()) { tk-=cnt[now].size();now++; } return GetAns(cnt[now],tk,l+1);}int main(){ while(~scanf("%d %d",&n,&k)) { scanf("%s",s); len=strlen(s); num.clear(); for(int i=1;i<=len;++i) num.push_back(i); printf("%d\n",GetAns(num,k,0)); } return 0;}