您的位置:首页 > 其它

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

2017-04-29 17:31 369 查看
题意:给定长度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’填充,然后每次选择最小的字母填充是不可行的,为什么呢?

先看一下如果用这样的想法最多的字符串:



可以明显看出,’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
;
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);

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: