题意:
博主不喜欢写这一栏目 , 但是鉴于这个题意有点绕....
有n个字符串 , 你的任务是在可以旋转字符串的情况下找到一个拼接字符串使得拼成字符串长度最短的方式 , 例如aabb 与 bbcc可以拼接成aabbcc , 并输出在最短前提下的最小字典序字符串;
提示:
1. 一道dp题 , 思路并不复杂.
2. 题目中有一句: the state of any lock is not shorter than the state of its previous lock , 指字符串的长度是单调递增的 , 然而递增其实是不好处理的 , 因为后一个字符串可以和前几个字符串结合 , 这个状态没有办法表示
以上两个提示请仔细想想 , 如果你灵光一闪 , 就赶快动手吧
3. 续2 , 于是你可以把整个序列倒过来 , 字典序显然也要倒过来处理(但这并不是很难)
4. dp [ i ] [ j ] 表示处理完第i个 , 并且第i个字符串用的是以这个字符串第j个字符打头的旋转方式(有点绕 , 自行脑补) , 转移方程是不难得到的
注意:
1.超时问题: 本题还卡一个前缀后缀判断相等的方法 , 因为不熟悉后缀数组(甚至不知道能不能在这里用) , 博主用的是hash , 详情见same()函数
//
// main.cpp
// UVa1405
//
// Created by Fuxey on 15/10/20.
// Copyright © 2015年 corn.crimsonresearch. All rights reserved.
//
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <deque>
#include <list>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;
const int INF = 1<<29;
const ull hash_num = 10331007;
// d[i][j] upto i and end with the jth rotation of ith string
int d[250][150];
string s[250];
string rot[250][150];
ull hashes[250][150][150];
ull acu[200];
inline int same(int x1 , int y1 , int x2 , int y2)
{
for(int i=(int)min(s[x1].size(), s[x2].size());i>=0;i--)
if(hashes[x1][y1][s[x1].size()] == hashes[x2][y2][i]+hashes[x1][y1][s[x1].size()-i]*acu[i])
return i;
return -1;
}
bool smaller(string& s1 , string& s2)
{
for(int i=1;i<=min(s1.size(), s2.size());i++) if(s1[s1.size()-i]!=s2[s2.size()-i])
return s1[s1.size()-i]<s2[s2.size()-i];
return false;
}
int main(int argc, const char * argv[]) {
ios::sync_with_stdio(false);
acu[0] = 1;
for(int i=1;i<=120;i++) acu[i] = acu[i-1]*hash_num;
int t;
cin>>t;
while(t--)
{
string op;
cin>>op;
reverse(op.begin(), op.end());
int last = 0 , n = 0;
for(int i=0;i<op.size();i++)
{
for(;i<op.size() && op[i]!=';';i++) ;
s[++n] = op.substr(last , i-last);
last = i+1;
}
for(int i=1;i<=n;i++) rot[i][0] = s[i];
for(int i=1;i<=n;i++) for(int j=1;j<s[i].size();j++) rot[i][j] = rot[i][j-1].substr(1,s[i].size()-1)+rot[i][j-1][0];
for(int i=1;i<=n;i++) for(int j=0;j<s[i].size();j++) for(int k=1;k<=s[i].size();k++)
hashes[i][j][k] = hashes[i][j][k-1]*hash_num+(ull)(rot[i][j][k-1]-'A'+10);
for(int i=1;i<=n;i++) for(int j=0;j<s[i].size();j++) d[i][j] = INF;
for(int i=0;i<s[1].size();i++) d[1][i] = (int)s[1].size();
for(int i=2;i<=n;i++) for(int j=0;j<s[i].size();j++) for(int k=0;k<s[i-1].size();k++)
d[i][j] = min(d[i][j] , d[i-1][k]+(int)s[i].size()-same(i-1,k, i,j));
int sup = INF;
for(int i=0;i<s[n].size();i++) sup = min(sup , d[n][i]);
string Min = "[";
int x = 0;
for(int i=0;i<s[n].size();i++) if(d[n][i]==sup && smaller(rot[n][i] , Min)) Min = rot[n][i] , x = i;
string res = rot[n][x];
for(int i=n-1;i>=1;i--)
{
Min = "[";
int nextx = 0;
for(int j=0;j<s[i].size();j++)
if(d[i+1][x] == d[i][j]-same(i,j, i+1,x)+s[i+1].size() && smaller(rot[i][j] , Min))
Min = rot[i][j] , nextx = j;
int h = same(i, nextx, i+1,x);
res = rot[i][nextx].substr(0 , s[i].size()-h)+res;
x = nextx;
}
reverse(res.begin(), res.end());
cout<<res<<endl;
}
return 0;
}