您的位置:首页 > 其它

Ural 1706. Cipher Message 2 后缀数组

2013-08-14 09:54 369 查看


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 = s1s2…sn.
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:

The string qi is considered consisting of k consecutive symbols of the string s starting from the ith: qi = sisi + 1…si + 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 =si…sns1…si + k − 1 − n.
For the string qi, the number of its different nonempty substrings mi is
calculated.

The sequence m1, m2, …, 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 m1, m2,
…, mn separated with spaces.

Sample

inputoutput
3
abaccc

5 6 5 3 5 6

Problem Author: Dmitry Ivankov

Problem Source: The 13th Urals Collegiate Programing Championship, April 04, 2009
题意:二战的背景,为了将数据传送到中心,Stierlitz使用以下算法:

输入一个字符串s = s1s2…sn.

选择密钥K,是一件正面小于n的整数。

对于每一个符号SI的字符串,下面的程序适用于:

被认为是由k个连续符号的字符串s从i开始串qi :qi = sisi + 1…si + k − 1.。如果有小于k符号,直到结尾的字符串,那么剩下的符号都取自开头的字符串:qi =si…sns1…si + k − 1 − n.。

对于串qi,输出其不同的非空的子串中号的数量m1, m2,
…, 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: