Ural 1706. Cipher Message 2 后缀数组

来源:互联网 发布:北京java工资水平 编辑:程序博客网 时间:2024/05/20 23:30

1706. Cipher Message 2

Time limit: 3.0 second
Memory limit: 64 MB
Müller had been suspecting for a long time that Stierlitz had been sending cipher messages to the USSR from time to time. And now Müller almost got the proof of that. Rummaging through Stierlitz's papers, he found a strange sequence of digits written on a clean sheet of paper. He guessed that it was a cipher message and called Stierlitz for questioning. But Stierlitz calmly answered that the digits were the number of a lottery-ticket that he had written in order not to forget it. Stierlitz had never been so close to a failure: there were the coordinates of Hitler's bunker on the sheet.
For transmitting the data to the center, Stierlitz used the following algorithm:
  • The input is a string s = s1s2sn.
  • A key k is chosen; it is a positive integer smaller than n.
  • For every symbol si of the string, the following procedure is applied:
    1. The string qi is considered consisting of k consecutive symbols of the string s starting from the ith: qi = sisi + 1si + k − 1. If there are less than k symbols till the end of the string, then the remaining symbols are taken from the beginning of the string: qi =sisns1si + k − 1 − n.
    2. For the string qi, the number of its different nonempty substrings mi is calculated.
  • The sequence m1m2, …, mn is the output of the algorithm.
It is not easy to cipher with this algorithm, and how to decode the messages only the Soviet intelligence service knows. You are given a chance to feel yourself the famous Stierlitz for several minutes.

Input

In the first line you are given the key k, 1 ≤ k ≤ 1000. The second line contains the string s you are supposed to cipher. The string consists of lowercase English letters, and its length is strictly greater than k and does not exceed 4000.

Output

Output the numbers m1m2, …, mn separated with spaces.

Sample

inputoutput
3abaccc
5 6 5 3 5 6
Problem Author: Dmitry Ivankov
Problem Source: The 13th Urals Collegiate Programing Championship, April 04, 2009
题意:二战的背景,为了将数据传送到中心,Stierlitz使用以下算法:
输入一个字符串s = s1s2sn.
选择密钥K,是一件正面小于n的整数。
对于每一个符号SI的字符串,下面的程序适用于:
被认为是由k个连续符号的字符串s从i开始串qi qi = sisi + 1si + k − 1.。如果有小于k符号,直到结尾的字符串,那么剩下的符号都取自开头的字符串:qi =sisns1si + k − 1 − n.。
对于串qi,输出其不同的非空的子串中号的数量m1m2, …, mn
首先先把字符串复制一遍,之后再利用height相减即为k个的字符串
#include<iostream>#include<cstring>#include<cstdio>using namespace std;const int MAX = 8005;int sa[MAX], rk[MAX], height[MAX];int wa[MAX], wb[MAX], wv[MAX], wd[MAX];int cmp(int *r, int a, int b, int l){    return r[a] == r[b] && r[a+l] == r[b+l];}int min(int a,int b){    return a<b? a:b;}void da(int *r, int n, int m)            //  倍增算法0(nlgn)。m是r中元素的最大值{    int i, j, p, *x = wa, *y = wb, *t;    for(i = 0; i < m; i ++) wd[i] = 0;    for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++;    for(i = 1; i < m; i ++) wd[i] += wd[i-1];    for(i = n-1; i >= 0; i --) sa[-- wd[x[i]]] = i;    for(j = 1, p = 1; p < n; j *= 2, m = p)    {        for(p = 0, i = n-j; i < n; i ++) y[p ++] = i;        for(i = 0; i < n; i ++) if(sa[i] >= j) y[p ++] = sa[i] - j;        for(i = 0; i < n; i ++) wv[i] = x[y[i]];        for(i = 0; i < m; i ++) wd[i] = 0;        for(i = 0; i < n; i ++) wd[wv[i]] ++;        for(i = 1; i < m; i ++) wd[i] += wd[i-1];        for(i = n-1; i >= 0; i --) sa[-- wd[wv[i]]] = y[i];        for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i ++)        {            x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1 : p ++;        }    }}void calHeight(int *r, int n)            //  求height数组。{    int i, j, k = 0;    for(i = 0; i < n; i ++) rk[sa[i]] = i;    for(i = 0; i < n; height[rk[i ++]] = k)    {        for(k ? k -- : 0, j = sa[rk[i]-1]; r[i+k] == r[j+k]; k ++);    }}char str[8000];int r[8005];int main(){    int k;    int i;    while(~scanf("%d",&k))    {        scanf("%s",str);        int l=strlen(str);        int w=l;        for(i=0; i<l; i++)            str[l+i]=str[i];        l=l+l;        str[l]='#';        l++;        int j;        for(i=0; i<w; i++)        {            int cnt=0;            for(j=i; j<i+k; j++)                r[cnt++]=str[j];            r[cnt++]=0;            da(r,cnt,260);            calHeight(r,cnt);            int k,ret=0;            for(k=1; k<cnt; k++)            {                ret+=cnt-1-sa[k]-height[k];            }            printf("%d",ret);            if(i!=w-1)                printf(" ");            else                printf("\n");        }    }    return  0;}