1 条题解

  • 0
    @ 2025-8-24 21:27:14

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar xgzc
    苔花如米小,也学牡丹开。

    搬运于2025-08-24 21:27:13,当前版本为作者最后更新于2017-09-23 19:59:41,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    看大家都是N^4或N³算法,N²算法还没有,赶紧水一发

    基本思路:

    把所有串连接起来,记录每个串的尾后位置,

    设f[k][i]表示现在在处理缩写的第K个字符,在大字符串中第I个位置对前面字符的总贡献数,则f[k][i]=Σf[k-1][j],

    其中j表示满足条件的前一个缩写字符。其中满足条件的定义为“无空缺单词,且是前一个字母”。则答案为Σf[最后一个字符][j],(1<=j<=n)。

    为避免出现同一字母出现位置的不同,用一个数组进行标记即可。

    ###标记要一次打完才能更新!!!

    #include<bits/stdc++.h>
    #define RG register
    using namespace std;
    
    int n;
    char a[110][200];//无效单词
    char c1[200];
    char c[200];
    char all[200][200];//有效单词
    int ma[26][200];//每个字母的有效位置
    int tag[200];
    int tag1[200];//两个标记
    int cut[200];//单词的尾后位置
    int sum[26];//出现的次数
    int f[200][200];//dp数组
    
    int main()
    {
        scanf("%d\n",&n);
        for(RG int i=1;i<=n;i++)
        {
            scanf("%s",a[i]);
        }
        scanf("%s",c1);
        while(1)
        {
            RG int i_1_1=1;
            strcpy(c,c1);
            if(strcmp(c,"LAST")==0)
            {
                scanf("%s",all[i_1_1++]);
                if(strcmp(all[i_1_1-1],"CASE")==0) break;
            }
            while(cin>>all[i_1_1++])
            {
                RG int j=0;
                int len=strlen(all[i_1_1-1]);
                while(all[i_1_1-1][j]<'a'&&j<len) j++;
                if(j>=len)
                {
                    strcpy(c1,all[i_1_1-1]);
                    i_1_1--;
                    break;
                }
                else
                {
                    for(RG int i=1;i<=n;i++)
                    {
                        if(strcmp(a[i],all[i_1_1-1])==0)
                        {
                            i_1_1--;
                            break;
                        }
                    }
                }
            }
            i_1_1--;
            printf("%s ",c);
            int len=strlen(c);
            for(RG int i=0;i<len;i++)
            {
                c[i]=c[i]+32;
            }
            //读入
            if(len<i_1_1)//分类讨论
            {
                puts("is not a valid abbreviation");
            }
            else if(len==i_1_1)
            {
                int ans=1;
                for(RG int i=0;i<len;i++)
                {
                    int len2=strlen(all[i+1]);
                    RG int tmp=0;
                    for(RG int j=0;j<len2;j++)
                    {
                        if(all[i+1][j]==c[i]) tmp++;
                    }
                    if(tmp) ans*=tmp;
                    else
                    {
                        puts("is not a valid abbreviation");
                        break;
                    }
                }
                printf("can be formed in %d ways\n",ans);
            }
            else //重点
            {
                memset(sum,0,sizeof(sum));
                memset(f,0,sizeof(f));
                memset(tag,0,sizeof(tag));
                memset(cut,0,sizeof(cut));
                memset(ma,0,sizeof(ma));
                int cz=strlen(all[1]);
                for(int i=2;i<=i_1_1;i++)
                {
                     strcpy(all[1]+cz,all[i]);
                     cut[i-1]=cz;
                     cz=strlen(all[1]);
                }
                //连串
                cut[i_1_1]=cz;
                for(int i=0;i<cz;i++)
                {
                    int j=all[1][i]-'a';
                    ma[j][++sum[j]]=i;
                }
                //记字母位置
                for(int k=0;k<len;k++)
                {
                    int id=c[k]-'a';
                    int ci=min(k+1,i_1_1);
                    int ti=1;
                    for(int i=0;i<cz;i++)
                    {
                        tag1[i]=tag[i];
                    }//备份
                    for(int i=1;i<=sum[id]&&ma[id][i]<cut[ci];i++)
                    {
                        while(ma[id][i]>=cut[ti]) ti++;
                        if(i_1_1-ti>len-k-1) continue;
                        if(k==0)
                        {
                            tag1[ma[id][i]]=0;//标记
                            f[k][i]=1;//初始值
                        }
                        else
                        {
                            int t=c[k-1]-'a';
                            for(int j=1;j<=sum[t];j++)
                            {
                                if(ma[t][j]<ma[id][i]&&ma[t][j]>=cut[ti-2]&&tag[ma[t][j]]==k-1)
                                {
                                    f[k][i]+=f[k-1][j];//转移
                                    tag1[ma[id][i]]=k;//标记×2
                                }
                            }
                        }
                    }
                    for(int i=0;i<cz;i++)
                    {
                        tag[i]=tag1[i];//备份
                    }
                }
                int ans=0;
                for(int i=1;i<=sum[c[len-1]-'a'];i++)
                {
                    ans+=f[len-1][i];//求和
                }
                if(ans)
                {
                    printf("can be formed in %d ways\n",ans);
                }
                else puts("is not a valid abbreviation");
            }
        }
        return 0;
    }
    
    • 1

    信息

    ID
    617
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者