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