題目大意:
就是現在對於每一次給出的N <= 50W, 構造一個長度爲N的串只包含小寫字母且每一個長度>=4的子串都只出現一次
如果不可能就輸出Impossible
大致思路:
首先考慮到如果長度爲l + 1的串出現了兩次那麼長度爲l的串一定也出現了兩次
所以構造的串一定是所有長度爲四的串都只出現了一次
那麼能不能對於所有的長度爲4的串都出現呢
一共有26*26*26*26種可能的長度爲4的子串
我們從狀態轉移的角度進行考慮
考慮4個字母的串, 在後面沒加上一個字符, 就變成另外4個字母組成的串結尾的狀態
例如aaaa結尾通過添加字符b變成aaab結尾再添加c變成aabc結尾
那麼對於每一個長度爲4的串一共有26種可能的轉移
於是我們可以得到一個26*26*26*26個點的有向圖的轉移, 每個點有26個出邊26個入邊, 於是這個圖一定存在歐拉回路, 那麼我們從任意一個點開始一定能找到一條路徑走過每個點恰好一次
於是得出結論:這個串最大長度是26*26*26*26 + 3, 對於大於這個長度的N直接判Impossible否則輸出前N個字符即可
代碼如下:
Result : Accepted Memory : 15556 KB Time : 187 ms
/*
* Author: Gatevin
* Created Time: 2015/10/6 12:57:29
* File Name: Sakura_Chiyo.cpp
*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
char s[500010];
char res[500010];
const int m1 = 26, m2 = 26*26, m3 = 26*26*26;
bool vis[26*26*26*26];
int result = -1;
const int maxn = 26*26*26*26;
bool dfs(int now, int dep)
{
//vis[now] = 1;
if(dep == maxn)
{
for(int i = 0; i < dep + 3; i++)
res[i] = s[i];
result = dep;
return true;
}
int p0 = now / m3;
int p1 = (now % m3) / m2;
int p2 = (now % m2) / m1;
int p3 = (now % m1);
for(int i = 0; i < 26; i++)
{
int nex = p1*m3 + p2*m2 + p3*m1 + i;
if(!vis[nex])
{
s[dep + 3] = 'a' + i;
vis[nex] = 1;
if(dfs(nex, dep + 1))
return true;
vis[nex] = 0;
}
}
return false;
}
int main()
{
s[0] = 'a';
s[1] = 'a';
s[2] = 'a';
s[3] = 'a';
vis[0] = 1;
dfs(0, 1);
int N;
while(~scanf("%d", &N))
{
if(N > maxn + 3)
{
puts("Impossible");
continue;
}
else for(int i = 0; i < N; i++)
putchar(res[i]);
putchar('\n');
}
return 0;
}