CodeForces 461E Appleman and a Game

Description

Appleman and Toastman like games. Today they play a game with strings with the following rules. Firstly Toastman tells Appleman two strings s and t both consisting only of letters ‘A’, ‘B’, ‘C’, ‘D’. Then Appleman must build string s as quickly as possible. Initially he has empty string, and in one second he can append to end of the current string any contiguous substring of t.

Now, Toastman and Appleman are beginning to play the game. Toastman has already told string t to Appleman, but he hasn’t come up with string s yet. Toastman only thinks, that he should choose string s consisting of n characters. Of course, he wants to find the worst string for Appleman (such string, that Appleman will spend as much time as possible during the game). Tell Toastman, how much time will Appleman spend during the game if Toastman finds the worst string for him. You can assume that Appleman plays optimally, therefore he builds any string s in minimal possible time.

Input

The first line contains an integer n (1 ≤ n ≤ 1018). The second line contains string t (1 ≤ |t| ≤ 105). String t consists of only letters ‘A’, ‘B’, ‘C’, ‘D’. Each letter appears at least once in string t.

Output

Print a single integer — the largest possible time Appleman needs.

Examples

input

5
ABCCAD

output

5

input

5
AAABACADBABBBCBDCACBCCCDDDBDCDD

output

4

Note

In the first example, Toastman can choose s equal to “AAAAA”.
In the second example, Toastman can choose s equal to “DADDA”.

题目大意

需要你构造一个字符串s,使得用字符串t来拼s的次数最多。
每次,可以从t中取出连续的一段,加到s中去。
假设是最优策略。

题解

最终构造出来的字符串s一个是由无数段t中的连续的字符串构成的。
如果想让次数更多,那么尽可能使得每一个段最短。
fi,j 表示以i作为开头,在其结尾放j,并不会产生一个新的t的子串。
用倍增的思想将他们不断合并产生新的串。
求答案的时候就将这些串合并一下。
观察可以发现,trie只需要建深度为 log4n 的,剩下的是不可能成为最优解的。

code

#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 10000003
#define M 103
#define db double
#define P putchar
#define G getchar
#define inf 998244353
#define fori for(int i=0;i<4;i++)
#define forj for(int j=0;j<4;j++)
#define fork for(int k=0;k<4;k++)
using namespace std;
char ch;
void read(ll &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    ll w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

int max(int a,int b){return a>b?a:b;}
ll min(ll a,ll b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

int trie[N][4],T[N],tot,x,y,len;
ll log_4,t,n,f[5][5][80],g[5][5],ans,p[5][5],z[80],lim,mi;
bool now;

void dfs(int xx,int x,int y,int l)
{
    if(l>=f[xx][y][0])return;
    if(trie[x][y]==0)
    {
        f[xx][y][0]=l;
        return;
    }

    fori if(trie[x][i])dfs(xx,trie[x][i],y,l+1);

}

int main()
{
    read(n);
    t=tot=1;
    for(ch=G();ch<'A' || ch>'D';ch=G());
    for(len=0;'A'<=ch && ch<='D';ch=G())T[++len]=ch-'A';

    for(log_4=0;t*4<=len;log_4++)t=t<<2;
    log_4++;

    for(int i=1;i<=len;i++)
    {
        x=1;y=min(i+log_4-1,len);
        for(int j=i;j<=y;x=trie[x][T[j]],j++)
            if(trie[x][T[j]]==0)trie[x][T[j]]=++tot;
        //write(tot);P('\n');
    }

    //build trie

    fori forj f[i][j][0]=inf;
    fori forj 
        if(trie[1][i] && trie[1][j])dfs(i,trie[1][i],j,1);

    //初始化
    //f[i('A'..'D')][j('A'..'D')] 以i开头,结尾后加上j,j不会被同一次覆盖,最短长度。 

    z[0]=1,z[1]=2;
    for(int I=1;z[I]<=n;lim=I,I++)
    {
        z[I+1]=z[I]<<1;
        fori forj fork
        if(trie[1][i] && trie[1][j] && trie[1][k])
            if(f[i][j][I]==0 || f[i][k][I-1]+f[k][j][I-1]<f[i][j][I])
                f[i][j][I]=f[i][k][I-1]+f[k][j][I-1];
    }

    //倍增,不断合并两个串

    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
            printf("%d ",f[i][j][20]);
        printf("\n");
    }

    now=1;
     for(int I=lim;I>=0;I--)
    {
        mi=n<<1;
        if(now)
        {
            fori forj
                if(trie[1][i] && trie[1][j])
                    mi=min(mi,f[i][j][I]);
            if(mi<n)
            {
                now=0;
                ans+=z[I];
                fori forj g[i][j]=f[i][j][I];
            }
        }
        else
        {
            fori forj
            {
                p[i][j]=0;
                fork
                if(trie[1][i] && trie[1][j] && trie[1][k])
                    if(p[i][j]==0 || g[i][k]+f[k][j][I]<p[i][j])
                        p[i][j]=g[i][k]+f[k][j][I];
                if(trie[1][i] && trie[1][j])mi=min(mi,p[i][j]);
            }
            if(mi<n)
            {
                ans+=z[I];
                fori forj g[i][j]=p[i][j];
            }
        }
    }

    write(ans+1);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值