Codeforces Round #570 (Div. 3) E. Subsequences (easy version)

题目链接:http://codeforces.com/contest/1183/problem/E

题意:现在有一个字符串长度为 n n n,你需要从字符串中找 k k k个不同的子序列出来,每个子序列的代价为字符串长度减去子序列长度,问怎样使总代价和最小,如果找不到 k k k个直接输出 − 1 -1 1

解题心得:因为n和k都比较小,可以直接 B F S BFS BFS搜索,每次搜索从当前串枚举删去一个字符,产生新的字符串然后压入队列,但是需要判断重合,可以直接用字典树标记查重。



#include <bits/stdc++.h>
using namespace std;
typedef complex<double> cp;
typedef long long ll;
const int maxn = 2e5+100;
const double pi = acos(-1);

int node[maxn][30], pos = 0, n ,k;//node是记录字典树的结点,pos是按照顺序顺序安排字典树的节点
bool End[maxn];//记录当前节点是否是一个字符串的结束点
string s;

void Mark(string st) {//字典树标记
    int root = 0;
    for(int i=0;i<st.size();i++) {
        if(node[root][st[i]] == 0) {
            node[root][st[i]] = ++pos;
            root = pos;
        } else {
            root = node[root][st[i]];
        }
        if(i == st.size()-1) {
            End[root] = true;
        }
    }
}

bool checke(string st) {//字典树查重
    int root = 0;
    for(int i=0;i<st.length();i++) {
        if(node[root][st[i]] == 0) return true;
        root = node[root][st[i]];
        if(i == st.length()-1) {
            if(End[root]) return false;
        }
    }
    return true;
}

bool Empty;

void BFS() {
    int ans = 0;
    queue <string> qu;
    qu.push(s);
    Mark(s);

    while(!qu.empty()) {
        string now = qu.front(); qu.pop();
        ans += (n - now.length());
        k--;//每次搜索减一
        if(k == 0) {
            printf("%d\n", ans);
            return ;
        }

        for(int i=0;i<now.length();i++) {
            string temp2 = now;
            temp2.erase(temp2.begin()+i);
            if(Empty && temp2.length() == 0) continue;
            if(checke(temp2)) {
                if(temp2.length() == 0) Empty = true;
                Mark(temp2);
                qu.push(temp2);
            }
        }
    }
    puts("-1");//找不到到k个
}

int main() {
//    freopen("1.in.txt", "r", stdin);
    scanf("%d%d",&n, &k);
    cin>>s;

    BFS();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值