UVa 1405 - The Ultimate Password

23 篇文章 0 订阅

题意:

博主不喜欢写这一栏目 , 但是鉴于这个题意有点绕....

有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;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值