1 条题解

  • 0
    @ 2025-8-24 22:10:35

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar foreverlasting
    果然,失去别人远比自己离去更加令人恐惧。

    搬运于2025-08-24 22:10:35,当前版本为作者最后更新于2018-08-03 18:57:34,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    题面

    写晕了写晕了,肝了一个下午加半个晚上,人都做懵了,幸亏BZOJ和UOJ都是跑最快的,不然感觉巨亏。

    感觉思路不简单,代码也超级难写。

    这题其实和【WC2004】孪生项链超级像,只不过这题代码更难写,也更恶心一点。

    我们考虑数位DP。

    怎么写DP?

    从前往后扫描每个位置,从大到小枚举每个字符,计算以当前确定部分为前缀的方案总数。

    那么如果方案总数>=k,说明这个位置不用弄了,直接进入下个位置。否则让k-=方案总数,去枚举下个字符。

    接下来重点就是如何记录方案总数,想法当然就是之前提过的数位DP。

    f[i][j][k]表示第i位已匹配的j位未匹配k位的方案总数。

    枚举当前使用的字符,用KMP转移,由于已经知道了最大匹配长度,那么当前添加的字符就不能超过最大匹配的下一位。

    事实上,已经确定的位置无需再计算方案总数,所以我们从未知的位置开始就行了。

    而第i位的匹配情况只与第i-1位的匹配情况有关,所以这完全可以滚动一下。

    具体转移以及各种细节参见代码吧。

    code:

    //2018.8.3 by ljz
    #include<bits/stdc++.h>
    using namespace std;
    #define res register LL
    #define LL long long
    #define inf 0x3f3f3f3f
    #define eps 1e-15
    inline LL read(){
        res s=0;
        bool w=0;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=1;ch=getchar();}
        while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
        return w?-s:s;
    }
    inline void _swap(res &x,res &y){
        x^=y^=x^=y;
    }
    inline LL _abs(const res &x){
        return x>0?x:-x;
    }
    inline LL _max(const res &x,const res &y){
        return x>y?x:y;
    }
    inline LL _min(const res &x,const res &y){
        return x<y?x:y;
    }
    const LL C=30,CH=26,N=50+10;
    const char max_char=CH+'a'-1;
    LL n,k,len;
    LL pre[N],next[N][C],minchar[N],ret[N];
    LL f[2][N][N],dp[N][N];
    char s[N<<1];
    inline bool judge(){
        for(res i=0;i<len;i++)s[i+len]=s[i];
        for(res i=1;i<len;i++){
            res j;
            for(j=0;j<len;j++)if(s[j]!=s[i+j])break;
            if(j==len||s[i+j]<s[j])return 0;
        }
        return 1;
    }
    inline bool inc(){
        while(len&&s[len-1]==max_char)len--;
        if(!len)return 0;
        s[len-1]++;
        return 1;
    }
    inline LL get_tot(){
        memset(next[0],0,sizeof(next[0]));
        pre[0]=-1;
        minchar[0]=0;
        for(res i=0;i<len;i++){
            res c=s[i]-'a';
            if(c<minchar[i])return 0;
            minchar[i]=c;
            next[i][c]=i+1;
            if(pre[i]==-1)pre[i+1]=0;
            else pre[i+1]=next[pre[i]][c];
            minchar[i+1]=minchar[pre[i+1]];
            for(res j=0;j<CH;j++)next[i+1][j]=next[pre[i+1]][j];
        }
        for(res i=0;i<=len;i++){
            ret[i]=0;
            res j=i;
            for(res k=0;k<len;k++){
                if(s[k]-'a'<minchar[j]){ret[i]=-1;break;}
                j=next[j][s[k]-'a'];
                if(j==len)ret[i]++;
            }
        }
        memset(f,0,sizeof(f));
        memset(dp,0,sizeof(dp));
        f[len&1][pre[len]][0]=1;
        for(res i=len;i<=n;i++){
            memset(f[(i+1)&1],0,sizeof(f[(i+1)&1]));
            for(res j=0;j<len;j++)
                for(res k=0;k<=n-len;k++){
                    if(ret[j]>=0)dp[i][k+ret[j]]+=f[i&1][j][k];
                    if(i==n)continue;
                    if(f[i&1][j][k]){
                        if(j+1==len)f[(i+1)&1][pre[len]][k+1]+=f[i&1][j][k];
                        else f[(i+1)&1][j+1][k]+=f[i&1][j][k];
                        f[(i+1)&1][0][k]+=f[i&1][j][k]*(CH-1-minchar[j]);
                    }
                }
        }
        for(res i=pre[len];i;i=pre[i]){
            if(ret[len-i]>=0)
                for(res j=2;j*(len-i)<=n;j++)
                    if(j*(len-i)>=len)dp[j*(len-i)][j]--;
            if((len-i)*2<len)i=(i-1)%(len-i)+1;
        }
        for(res i=len;i<=n;i++)
            for(res j=1;j<=i;j++)
                if(dp[i][j])for(res k=2;i*k<=n;k++)dp[i*k][j*k]-=dp[i][j];
        res ans=0;
        for(res i=len;i<=n;i++)
            for(res j=1;j<=i;j++)
                if(dp[i][j])ans+=dp[i][j]/j;
        return ans;
    }
    int main(){
        n=read(),k=read();
        scanf("%s",s);
        len=strlen(s);
        while(233){
            res tot=get_tot();
            if(tot<k){
                k-=tot;
                if(!inc()){puts("-1");return 0;}
            }
            else {
                if(judge())
    			    if(--k==0)break;
                s[len++]='a';
            }
        }
        for(res i=0;i<len;i++)putchar(s[i]);
        return 0;
    }
    
    • 1

    信息

    ID
    4397
    时间
    2000ms
    内存
    500MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者