• uoj #172. 【WC2016】论战捆竹竿


    #172. 【WC2016】论战捆竹竿

    这是一个美好的下午,小 W 和小 C 在竹林里切磋捆竹竿的技艺。

    竹林里有无数根完全一样的短竹子,每一根竹子由 nn 节组成。

    这些竹子比较特别,每一节都被染上了颜色。可能的颜色一共 2626 种,分别用小写英文字母 a 到 z 表示。也就是说,如果把竹子的底端到顶端的颜色按顺序写出来可以排成一个由小写英文字母组成的字符串。

    小 W 和小 C 都是捆竹竿的高手,他们知道怎样才能把零散的短竹子捆成一整根长竹竿。初始时你拿着一根短竹子作为当前的竹竿。每次你可以选择一根短竹子,短竹子底端若干节(可以是 00 节)与竹竿的最上面若干节对应地一节一节捆起来,而短竹子前面剩下的节伸出去,这样就得到了一根更长的竹竿。注意,竹子的底端是靠近根部的那一端,不可以颠倒。

    小 W 对竹竿的审美要求很高,他捆竹竿时有一个癖好:如果两根竹子的某两节被捆在了一起,那么它们的颜色必须相同。

    我们假设一根短竹子从底端到顶端每节的颜色为 aba

    那么两根竹子可以首尾捆在一起,可以得到一根颜色为 abaaba 的竹竿;也可以将第一根顶端的一节 a 与第二根底端的一节 a 捆在一起,得到一根颜色为 ababa 的竹竿;还可以直接将每一节都对应起来,捆成一根颜色为 aba 的竹竿。

    假设我们在颜色为 ababa 的竹竿顶端再捆一根竹子,则可以捆成 ababaabaabababa 和 ababa 三种不同的情况。

    但是小 C 在这个问题上有不同的看法,他认为小 W 捆不出很多种长度不同的竹竿。小 W 非常不服,于是他找到了你——现在请你求出在竹竿长度不超过 ww 的情况下,小 W 可以捆出多少种长度不同的竹竿。其中,竹竿的长度指从底端到顶端的竹子的节的个数。

    注意:如果 w<nw<n,则没有合法的长度,此时答案为 00。

    输入格式

    第一行包含 11 个正整数 TT,为数据组数。

    每组数据的第一行包含 22 个正整数 nn 和 ww,表示短竹子的长度和竹竿的长度上限。

    每组数据的第二行包含一个长度为 nn 的字符串,该字符串仅由小写英文字母构成,表示短竹子从底端到顶端每节的颜色。

    输出格式

    输出共 TT 行,每行包含一个整数表示捆成竹竿的不同长度种数。

    样例一

    input

    1
    4 11
    bbab
    
    

    output

    5
    
    

    explanation

    可以捆成长度不超过 1111 的竹竿有 66 种不同的情况:

    1. bbab
    2. bbabbab
    3. bbabbbab
    4. bbabbabbab
    5. bbabbabbbab
    6. bbabbbabbab

    后两种竹竿长度相同,因此不同长度的竹竿共有 55 种。长度分别为:4,7,8,10,114,7,8,10,11。

    样例二

    input

    2
    44 1000
    baaaaaabaabbaaabbbbabbbaaabbbababaaabaaabaaa
    41 1000
    abaabbabaaabaabbbbbbbbbbbababbbbaaabaabbb
    
    

    output

    195
    24
    
    

    样例三

    见样例数据下载。

    限制与约定

    对于所有的测试数据,保证所有的字符串均由小写字母构成,保证 T=5T=5。

    各测试点满足以下约定:

    测试点编号nnww约束
    1 10≤10 10≤10 ss 仅包含字母 a 和 b
    2 20≤20 20≤20
    3 100≤100 1018≤1018
    4
    5 103≤103
    6
    7 5×104≤5×104 105≤105
    8
    9
    10
    11 7×104≤7×104 1018≤1018
    12
    13 105≤105
    14
    15
    16
    17 5×105≤5×105
    18
    19
    20

    时间限制:1s1s

    空间限制:256MB

    /*
        可能是因为string导致7~10爆了空间
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 500010
    using namespace std;
    int n,w,nxt[maxn],ans;
    string s;
    bool vis[maxn];
    void getnxt(){
        int i=0,j=-1;
        nxt[0]=-1;
        while(i!=n){
            if(s[i]==s[j]||j==-1)nxt[++i]=++j;
            else j=nxt[j];
        }
    }
    void dfs(string c,int len){
        if(!vis[len]&&len<=w)vis[len]=1,ans++;
        else return;
        int j=nxt[n];
        while(j){
            dfs(c+s.substr(j,n-j),len+(n-j));
            j=nxt[j];
        }
        dfs(c+s,len+n);
    }
    int main(){
        int T;scanf("%d",&T);
        while(T--){
            memset(vis,0,sizeof(vis));ans=0;
            scanf("%d%d",&n,&w);cin>>s;
            getnxt();
            dfs(s,n);
            printf("%d
    ",ans);
        }
    }
    10分 kmp暴力
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long
    using namespace std;
    inline int read()
    {
        int t=1,sum=0;char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-') t=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
            sum=sum*10+ch-'0',ch=getchar();
        return t*sum;
    }
    const int Max=1e6+10;
    const LL inf=1e18;
    int nxt[Max],q[Max],Q[Max],len[Max],n,nm;
    LL f[Max],w[Max],W; char s[Max];
    void get_nxt()
    {
        int i,j;
        for(nxt[1]=j=0,i=2;i<=n;i++)
        {
            while(j&&s[j+1]!=s[i]) j=nxt[j];
            nxt[i]=s[j+1]==s[i]?++j:j;
        }
    }
    int gcd(int a,int b)
    {
        return !b?a:gcd(b,a%b);
    }
    void change(int x)
    {
        int d=gcd(x,nm),i,j,tot; static LL pre[Max];
        for(i=0;i<nm;i++) pre[i]=f[i];
        for(i=0;i<x;i++) f[i]=inf;
        for(i=0;i<nm;i++) 
            if(pre[i]!=inf)
                j=pre[i]%x,f[j]=min(f[j],pre[i]);
        for(i=0;i<d;i++)
        {
            tot=0; j=i;
            while(true)
            {
                q[++tot]=j;
                j=(j+nm)%x;
                if(j==i) break;
            }
            for(j=1;j<=tot;j++) q[tot+j]=q[j];
            tot<<=1;
            for(j=2;j<=tot;j++) f[q[j]]=min(f[q[j]],f[q[j-1]]+nm);
        }
        nm=x;
    }
    void update(int a0,int d,int num)
    {
        int D=gcd(d,a0),i,j,k,tot,N,l,r; 
        static LL w[Max],mi; change(a0);
        for(i=0;i<D;i++)
        {
            tot=0; j=i;
            while(true)
            {
                q[++tot]=j;
                j=(j+d)%a0;
                if(j==i) break;
            }
            for(mi=inf,j=1;j<=tot;j++) if(f[q[j]]<mi) mi=f[q[j]],k=j;
            if(mi==inf) continue;
            else N=0;
            for(j=k;j<=tot;j++) Q[++N]=q[j];
            for(j=1;j<k;j++) Q[++N]=q[j];
            q[1]=l=r=1; w[1]=f[Q[1]]-d;
            for(j=2;j<=N;j++)
            {
                if(q[l]+num<=j) l++;
                if(l<=r) f[Q[j]]=min(f[Q[j]],w[l]+1LL*j*d+a0);
                while(l<=r&&w[r]>=f[Q[j]]-1LL*j*d) r--;
                q[++r]=j; w[r]=f[Q[j]]-1LL*j*d;
            }
        }
    }
    int main()
    {
        int T=read(),i,j,k; LL ans;
        while(T--)
        {
            n=read(); scanf("%lld",&W); W-=n;
            scanf("%s",s+1); get_nxt();
            if(W<0)
            {
                puts("0");
                continue;
            }
            for(j=0,i=nxt[n];i;i=nxt[i]) len[++j]=n-i;
            for(i=1;i<=(j>>1);i++) swap(len[i],len[j-i+1]);
            for(f[0]=0,i=1;i<n;i++) f[i]=inf;
            nm=n;
            for(i=1;i<=j;i=k)
            {
                if(i==j) 
                {
                    update(len[i],1,1);
                    break;
                }
                for(k=i+1;k<=j&&len[i]-len[i+1]==len[k-1]-len[k];k++);
                update(len[k-1],len[i]-len[i+1],k-i);
            }
            for(ans=i=0;i<nm;i++)
                if(f[i]!=inf&&f[i]<=W)
                    ans+=(W-f[i])/nm+1;
            printf("%lld
    ",ans);
        }
        return 0;
    }
    100分 完全不明白
  • 相关阅读:
    第四周作业
    jsp第二次作业
    jsp第一次作业
    软件测试1
    activity
    listview
    sql
    登录
    第二次安卓作业
    安卓第一周作业
  • 原文地址:https://www.cnblogs.com/thmyl/p/8098574.html
Copyright © 2020-2023  润新知