URAL 1002 Phone Numbers

传送门
直接求出每个串出现位置,DP即可。

#include <bits/stdc++.h>
using namespace std;
#define prt(k) cerr<<#k" = "<<k<<endl
typedef long long LL;
const int inf = 0x3f3f3f3f;
#define pb push_back
const int N = 50500;
const int M = N * 50;
int ch[M][10], fail[M], id[M], len[N];
int L; int n;
map<char, int> mp;
namespace AC {
int newnode() { memset(ch[L],-1,sizeof ch[L]); id[L++] = 0; return L-1; }
void init() { L = 0; newnode(); }
void insert(char s[], int ID)
{
    int u = 0, len = strlen(s);
    for (int i=0;i<len;i++) {
        int c = s[i] - '0';
        if (ch[u][c] == -1) ch[u][c]=  newnode();
        u = ch[u][c];
    }
    id[u] = ID;
}
void AC_build()
{
    queue<int> q;
    for (int i=0;i<10;i++) {
        int &v = ch[0][i];
        if (v != -1) {
            q.push(v);
            fail[v] = 0;
        } else v = 0;
    }
    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int i=0;i<10;i++) {
            int &v = ch[u][i];
            if (v==-1) {
                v = ch[fail[u]][i];
            } else {
                fail[v] = ch[fail[u]][i];
                q.push(v);
            }
        }
    }
}
vector<int> pos[N];
void query(char buf[])
{
    int n = strlen(buf);
    int u=0;
    for(int i=0;i<n;i++)
    {
        u=ch[u][buf[i]-'0'];
        for(int v=u;v!=0;v=fail[v])
        {
            if (id[v] > 0) {
                pos[i-len[id[v]]+1].push_back(id[v]);
            }
        }
    }
} };
using namespace AC;
#define For(i,l,r) for (char i=l;i<=r;i++)
char T[233], s[N][52], old[N][55];
int TL;
int dp[N];
int pre[N];
int main()
{
    mp['i'] = mp['j'] = 1;
    mp['a'] = mp['b'] = mp['c'] = 2;
    For(i,'d','f') mp[i]=3;
    For(i, 'g', 'h') mp[i] = 4;
    For(i,'k','l') mp[i] = 5;
    For(i,'m','n') mp[i] = 6;
    For(i,'p','s') mp[i] = 7;
    For(i, 't', 'v') mp[i] = 8;
    For(i, 'w', 'y') mp[i] = 9;
    mp['o'] = mp['q'] = mp['z'] = 0;
    while (scanf("%s", T) == 1 ) {
        if (strcmp(T,"-1")==0) break;
        TL = strlen(T);
        for (int i=0;i<TL;i++) pos[i].clear();
        cin>>n;
        L = 0; newnode();
        for (int i=1;i<=n;i++) {
            scanf("%s", s[i]);
            len[i] = strlen(s[i]);
            strcpy(old[i], s[i]);
            for (int j=0;j<len[i];j++) s[i][j] = mp[s[i][j]] + '0';
            insert(s[i], i);
        }
        AC_build();
        query(T);
        int m = TL;
        memset(dp, 63, sizeof dp);
        memset(pre, -1, sizeof pre);
        dp[0] = 0;
        for (int i=0;i<m;i++) {
            for (auto  x : pos[i]) {
                if (dp[i+len[x]] > dp[i] + 1) {
                    dp[i+len[x]] = dp[i] + 1;
                    pre[i+len[x]] = x;
                }
            }
        }
        if (dp[m] == inf) { puts("No solution."); continue; }
        stack<int> stk;
        int i = m;
        while (i!=0 && pre[i]!=-1) {
            stk.push(pre[i]);
            i -= len[pre[i]];
        }
        printf("%s", old[stk.top()]);
        stk.pop();
        while (!stk.empty()) {
            printf(" %s", old[stk.top()]);
            stk.pop();
        }
        putchar(10);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值