HDU 4850 Wow! Such String!(构造推理)

本文介绍了一种构造特定字符串的方法,确保长度大于等于4的子串只出现一次。通过使用四维数组标记子串出现状态,并采用逆序填充策略,解决了字符串构造难题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给定长度n 找到一个满足
1.长度为n
2.全为小写字母
3.长度>=4的子串只出现一次 的字符串 没有则输出Impossible

开始的时候就一直觉得这道题有规律 纠结于找不到这样串的临界点究竟是什么时候……
后来发现我真的想多了 = =就一直推下去 推不到就是Impossible

具体推理过程就是用vis四维数组标记连续的串是否出现:
vis[i][j][k][l] 就是表示’a’+i ‘a’+j ‘a’+k ‘a’+l 是否出现

然后前面26*4都用相同字母aaaabbbbcccc……zzzz这样填充
之后一个字母一个字母推
每次用 最大的字母 且 加上该字母后连续串在vis数组出现过 的填充
填充完在vis数组中将该字母加上之前三个字母的连续串在vis数组中置1
用flag标记 当某个位置取得最小字母时都无法填充时 说明不可以组成这样的串

某一段字母样例为:
aaaabbbbccccddddeeeeffffgggghhhhiiiijjjjkkkkllllmmmmnnnnooooppppqqqqrrrrssssttttuuuuvvvvwwwwxxxxyyyyzzzz
yzzyyzyzyyyxzzzxzzyxzyzxzyyxyzzxyzyxyyzxyyxxzzxxzyxxyzxx

首先,如果反向推也是可行的,先从’z’~’a’填充,然后填充最小的字母zzzz…aaaabaab…
但是,如果’a’~’z’填充,然后每次选择最小的字母填充是不可行的,为什么呢?
先看一下如果用这样的想法最多的字符串:

pic1
可以明显看出,’a’过多的占用位置导致每4个位置的最后一个位置没有办法放下别的字母,如果需要继续放,必须改变第三个字母的再继续放入,想想就很麻烦
使用’z’~’a’的顺序用最大字母填充后面的位置能够改善这样的情况。

但是到底为什么这样可以出结果还是不知道啊

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 26*26*26*26+10;
const int N1 = 26*4;
int vis[30][30][30][30];
char s[N];
int main() {
    int n;
    while(~scanf("%d",&n)) {
        memset(vis,0,sizeof(vis));
        memset(s,0,sizeof(s));

        int cnt=0;
        char c='a';
        int temp=n>N1?N1:n;
        for(int i=0; i<temp; i++) {
            if(cnt>=4) {
                cnt=0;
                c++;
            }
            s[i]=c;
            cnt++;
        }
        int flag=0;
        if(n>N1) {

            for(int i=3; i<N1; i++) {
                vis[s[i-3]-'a'][s[i-2]-'a'][s[i-1]-'a'][s[i]-'a']=1;
            }

            for(int i=N1; i<n; i++) {
                flag=0;
                for(char j='z'; j>='a'; j--) {
                    if(vis[s[i-3]-'a'][s[i-2]-'a'][s[i-1]-'a'][j-'a']==0) {
                        flag=1;
                        s[i]=j;
                        vis[s[i-3]-'a'][s[i-2]-'a'][s[i-1]-'a'][j-'a']=1;
                        break;
                    }
                }
                if(!flag) {
                    break;
                }
            }
        } else flag=1;
        if(!flag) puts("Impossible");

        else printf("%s\n",s);


    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值