2019 Multi-University Training Contest 1 String(序列自动机+贪心)

题意:给你一个字符串 现在要你找出一个长度为k的字典序最小的子序列 且要求每个字母出现的个数要满足要求

思路:我们可以贪心构造每一位字符 优先放置字典序更小的字符 判断是否合法即可

#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1.0);
const int N = 1e5+7;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
typedef long long ll;
const ll mod = 1e7+9;
string s;
int l[N],r[N],suf[N][26],nex[N][26],use[26],k;
void work(string s){
    int len=s.length();
    for(int i=0;i<26;i++){
        suf[len+1][i]=0;
        nex[len+1][i]=-1;
        use[i]=0;
    }

    for(int i=len;i>=1;i--){
        for(int j=0;j<26;j++){
            suf[i][j]+=suf[i+1][j];
            nex[i][j]=nex[i+1][j];
        }
        suf[i][s[i-1]-‘a‘]++;
        nex[i][s[i-1]-‘a‘]=i;
    }
}
vector<char> ans;
bool check(int po,int sz){
    int len=0; int num=0;
    for(int i=0;i<26;i++){
        if(use[i]+suf[po][i]<l[i]) return false;
        len+=use[i]+min(suf[po][i],r[i]-use[i]);
        num+=max(0,l[i]-use[i]);
    }
    if(len<k) return false;
    if(num+sz>k) return false;
    return true;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    while(cin>>s>>k){
        memset(suf,0,sizeof(suf));
        memset(nex,0,sizeof(nex));
        ans.clear();
        for(int i=0;i<26;i++){
            cin>>l[i]>>r[i];
        }
        work(s);
        int now=0; int sz=0;
        bool f=1;
        int len=s.length();
        while(now+1<=len&&sz+1<=k){
            bool ff=0;
            for(int i=0;i<26;i++){
                if(nex[now+1][i]!=-1&&use[i]<r[i]){
                    use[i]++;
                    if(check(nex[now+1][i],sz+1)){
                        ans.push_back(i+‘a‘);
                        sz++;
                        now=nex[now+1][i];
                        ff=1;
                        break;
                    }
                    use[i]--;
                }
            }
            if(!ff){
                f=0;
                break;
            }
        }
        if(f){
            for(int i=0;i<sz;i++)
                cout<<ans[i];
            cout<<endl;
        }else{
            cout<<"-1"<<endl;
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/wmj6/p/11363630.html

时间: 2024-11-02 14:46:07

2019 Multi-University Training Contest 1 String(序列自动机+贪心)的相关文章

2018 Multi-University Training Contest 1 Distinct Values 【贪心 + set】

任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6301 Distinct Values Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5312    Accepted Submission(s): 1823 Problem Description Chiaki has an array of

C - Obtain The String 序列自动机

传送门:https://vjudge.net/contest/361562#problem/C 题意 多组样例,给你一个串s和串t还有一个空串x,要求往x里添加s的子序列,使x变为t,求添加次数. 思路 使用序列自动机狗仔串s的nxt数组,把整个t串进行匹配,当失配的时候,把前面已经匹配成功的部分当成一次子序列的添加,再从当前失配位置从头匹配,如果还是匹配失败则无法完成输出-1. AC代码 #include<iostream> #include<string.h> using na

杭电多校HDU 6586 String(序列自动机 贪心)题解

题意: 给你一个串,现需要你给出一个子序列,满足26个约束条件,\(len(A_i) >= L_i\) 且 \(len(a) <= R_i\), \(A_i\)为从a到z的26个字母. 思路: 先用序列自动机(?)构造出某个位置后每个字母的个数,每个字母 的第一个位置. 然后每次贪心地加入最小的字符,加入的条件为当前字母加入后,后面的字符满足剩余的条件. 即剩余的字母在不超R_i的情况下能构成k长度的串,剩余的字母\(A_i+\)已拿取字母\(A_i >= L_i\)且满足\(L_i\)

2019 HDOJ Multi-University Training Contest Stage 8(杭电多校)

中规中矩的一场. 题目链接:http://acm.hdu.edu.cn/contests/contest_show.php?cid=855 C: 定义函数f(d,k)为数字d在数字k中出现的次数.给定d和x,找到尽量大的k使得k<=x且f(d,k)==k. 很诡异的一题,最好的做法仍然是打表找规律.题解给了一个很神奇的结论:满足条件的k<1011且k的分布非常稀疏. 1 /* basic header */ 2 #include <bits/stdc++.h> 3 /* defin

2019 HDOJ Multi-University Training Contest Stage 10(杭电多校)

最后一场多校打得一般般. 题目链接:http://acm.hdu.edu.cn/contests/contest_show.php?cid=857 C: E: I: BFS水题. 1 /* Codeforces Contest 2019_mutc_10 2 * Problem I 3 * Au: SJoshua 4 */ 5 #include <queue> 6 #include <cstdio> 7 #include <vector> 8 #include <s

2019 HDOJ Multi-University Training Contest Stage 4(杭电多校)

很抱歉过了这么多天才补这场,最近真的挺忙的…… 出题人是朝鲜的(目测是金策工业?),挺难. 题目链接:http://acm.hdu.edu.cn/contests/contest_show.php?cid=851 A: 签到题. 对于当前的点,若其编号为偶数,则可与1相连使得边权贡献为0.否则从低位向高位找当前点编号的二进制表示的第一个0,使这个0变为1,其他位置变为0并检查新的数字是否小于等于n.若小于等于n则贡献为0,反之贡献为1. 1 /* basic header */ 2 #inclu

2019 HDOJ Multi-University Training Contest Stage 2(杭电多校)

服务器时不时爆炸,有点难受. 题目链接:http://acm.hdu.edu.cn/userloginex.php?cid=849 A: 神仙题.不可做题. B: dp. C: 推式子题. D: 边分治. E: 可以数学推理的题.但是显然打表更快找出规律.对打出来的结果做两次差分即可. 1 /* basic header */ 2 #include <bits/stdc++.h> 3 /* define */ 4 #define ll long long 5 #define dou doubl

2019 Multi-University Training Contest 4.Divide the Stones(贪心)

题意:给你n和k (k|n) 有n个数 第i个数权值为i 要你求权值相同且分成k组 且每组的个数为n/k 思路:恶心构造题,首先对于总权值不能分为k份的 显然不能分成 然后 我们把n/k 分奇偶 我们可以发现 偶数我们可以每k个当成一组 对于奇数 我们可以先处理前3*k 然后同样处理剩下的数 #include <bits/stdc++.h> #define ls(x) T[x].ch[0] #define rs(x) T[x].ch[1] #define fa(x) T[x].fa #defi

2019 Nowcoder Multi-University Training Contest 1 H-XOR

由于每个元素贡献是线性的,那么等价于求每个元素出现在多少个异或和为$0$的子集内.因为是任意元素可以去异或,那么自然想到线性基.先对整个集合A求一遍线性基,设为$R$,假设$R$中元素个数为$r$,那么任取一个不在$R$内的元素,$R$中肯定存在一种取法能和这个元素异或和为$0$.同理,取定一个不在$R$内的元素,再随便取另外任意个不在$R$内的元素,$R$内仍然存在一种取法使得这个异或和为$0$.那么每个不在$R$内的元素包含在$2^{n - r - 1}$个集合内(其他不在$R$内的元素可以