题意:给出一个长为 n 的,由字母表中前 k 个小写字母组成的字符串 s.求一个长度为m的字符串,要求该串也只能由字母表前 k 个小写字母组成,且其不能是 s 的子串.

(题目指出一定有解)

方法一:在判重时采用这样的方法,想把原串中长度为m1的字串都求出hash值存入set中,然后从0开始寻找第一个未出现在set中的数,将其翻译成相应的字符串.

#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
using namespace std;
typedef long long ll;
const int N = 10010;
char s[N];
ll a[100];
set<ll>ss;
void print(int x,int m,int k)
{
    if(m==0)
    {
        return ;
    }
    print(x/k,m-1,k);
    printf("%c",x%k+'a');
}
int main(void)
{
    int T,n,m,k;
    scanf("%d",&T);
    while(T--)
    {
        ss.clear();
        scanf("%d%d%d",&n,&m,&k);
        scanf("%s",s);
        if(k==1)
        {
            for(int i=0;i<m;i++)
            {
                printf("%c",'a');
            }
            printf("\n");
        }
        else
        {
            int sum=k,tem=n;
            int m1=1;
            while(sum<=tem)   //算出当有几个字符时可能有不重复的字串
            {
                m1++;
                sum*=k;
                tem--;
            }
            if(m1>m) m1=m;
            a[0]=1;
            for(int i=1;i<=m1;i++)
            {
                a[i]=a[i-1]*k;
            }
            ll ans=0;
            for(int i=0;i<m1;i++)
            {
                ans=ans*k+s[i]-'a';
            }
            ss.insert(ans);
            for(int i=m1;i<n;i++)
            {
                ans-=a[m1-1]*(s[i-m1]-'a');
                ans=ans*k+s[i]-'a';
                ss.insert(ans);
            }
            for(int i=0;;i++)
            {
                if(ss.find(i)==ss.end())
                {
                    print(i,m1,k);
                    printf("\n");
                    break;
                }
            }
        }
    }
    return 0;
}



方法二:在判重时采用这样的方法,想把原串中长度为m1的字串都求出hash值存入ss数组中,然后经过sort,unique得到的是有序的字串,扫一遍即可.


#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 10010;
char s[N];
ll a[100];
ll ss[20000];
void print(int x,int m,int k)
{
    if(m==0)
    {
        return ;
    }
    print(x/k,m-1,k);
    printf("%c",x%k+'a');
}
int main(void)
{
    int T,n,m,k;
    scanf("%d",&T);
    while(T--)
    {
        memset(ss,0,sizeof(ss));
        scanf("%d%d%d",&n,&m,&k);
        scanf("%s",s);
        if(k==1)
        {
            for(int i=0;i<m;i++)
            {
                printf("%c",'a');
            }
            printf("\n");
        }
        else
        {
            int sum=k,tem=n;
            int m1=1;
            while(sum<=tem)   //算出当有几个字符时可能有不重复的字串
            {
                m1++;
                sum*=k;
                tem--;
            }
            if(m1>m) m1=m;
            a[0]=1;
            for(int i=1;i<=m1;i++)
            {
                a[i]=a[i-1]*k;
            }
            ll ans=0;
            for(int i=0;i<m1;i++)
            {
                ans=ans*k+s[i]-'a';
            }
            int pos=0;
            ss[pos++]=ans;
            for(int i=m1;i<n;i++)
            {
                ans-=a[m1-1]*(s[i-m1]-'a');
                ans=ans*k+s[i]-'a';
                ss[pos++]=ans;
            }
            sort(ss,ss+pos);
            unique(ss,ss+pos);
            for(int i=0;;i++)
            {
                if(ss[i]!=i)
                {
                    print(i,m1,k);
                    printf("\n");
                    break;
                }
            }
        }
    }
    return 0;
}