题目大意:给出一个字符串,以及8种变换方式,问说该字符串变换s次后的结果,注意字符串为环形,输出字典序最小的情况。
解题思路:因为字符串最长为15, 2^15<max(s), 所以一定会出现周期,暴力枚举周期。
#include <stdio.h>
#include <string.h>
#include <set>
using namespace std;
const int N = 20;
struct state {
int k, v;
friend bool operator < (const state& a, const state& b) {
return a.k < b.k;
}
};
int n, s, t[8];
set<state> rec;
char str[N];
void init() {
rec.clear();
char cha[N];
scanf("%s", str);
for (int i = 0; i < 8; i++) {
scanf("%s", cha);
int sum = 0;
for (int j = 0; j < 3; j++)
sum = cha[j] - 'a' + sum * 2;
t[sum] = cha[3] - 'a';
}
scanf("%d", &s);
}
int judge(char* a, char* b, int p, int& q) {
int sum;
for (int i = 0; i < n; i++) {
sum = (a[i] - 'a') * 4 + (a[(i+2)%n] - 'a') * 2 + a[(i+3)%n] - 'a';
b[(i+2)%n] = t[sum] + 'a';
}
b[n] = '\0';
sum = 0;
for (int i = 0; i < n; i++) sum = sum * 2 + b[i] - 'a';
state u;
u.k = sum; u.v = p;
set<state>::iterator it = rec.find(u);
if (it != rec.end()) {
q = it->v;
return p - q;
} else {
rec.insert(u);
return 0;
}
}
void solve() {
int cnt, q = 0;
bool flag = false;
char tmp[N];
for (int i = 0; i < n; i++) q = q * 2 + str[i] - 'a';
state u; u.k = q; u.v = 0;
rec.insert(u);
for (int i = 1; i <= s; i++) {
cnt = judge(str, tmp, i, q);
if (cnt) {
cnt = (s-q) % cnt;
flag = true;
break;
}
strcpy(str, tmp);
}
if (flag) {
cnt += q;
for (set<state>::iterator i = rec.begin(); i != rec.end(); i++) {
if (i->v == cnt) {
cnt = i->k; break;
}
}
for (int i = n-1; i >= 0; i--) {
tmp[i] = 'a' + cnt % 2;
cnt /= 2;
}
}
char ans[N];
strcpy(ans, tmp);
strcpy(str, tmp);
for (int i = 0; i < n; i++) {
tmp[0] = str[n-1];
strncpy(tmp+1, str, n-1);
if (strcmp(ans, tmp) > 0) strcpy(ans, tmp);
strcpy(str, tmp);
}
printf("%s\n", ans);
}
int main() {
while (scanf("%d%*c", &n) == 1) {
init();
solve();
}
return 0;
}