C

 

C - 字典序最小的子序列

Time Limit: 4000/2000 MS (Java/Others)      Memory Limit: 1280000/640000 KB (Java/Others)
Submit Status

Problem Description

给出一个由a-z组成的字符串S,求他的一个子序列,满足如下条件:
1、包含字符串中所有出现过的字符各1个。
2、是所有满足条件1的串中,字典序最小的。
例如:babbdcc,出现过的字符为:abcd,而包含abcd的所有子序列中,字典序最小的为abdc。

Input

单样例输入。

每个输入1行字符串S,所有字符均为小写,字符串的长度为L。(1 ≤ L ≤ 107)。

所有样例中只有一个样例 L > 105

Output

输出包含S中所有出现过的字符,每个字符各1个,并且字典序最小的S的子序列。

Sample Input

babbdcc

Sample Output

abdc


 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int N=1e7+10;
 5 const int INF=0x3f3f3f3f;
 6 int cas=1,T;
 7 char s[N],ans[N];
 8 int a[N],n;
 9 vector<int>q[26];
10 int main()
11 {
12 //  freopen("1.in","w",stdout);
13 //  freopen("21.in","r",stdin);
14 //  freopen("21.out","w",stdout);
15 //  scanf("%d",&T);
16     while(scanf("%s",s)==1)
17     {
18         int n=0;
19         for(;s[n];n++) q[s[n]-'a'].push_back(n);
20         a[n]=0;
21         for(int i=n-1;i>=0;i--)
22         {
23             int id=s[i]-'a';
24             a[i]=a[i+1]|(1<<id);
25         }
26         int d=0,an=0,id=0;
27         while(d!=a[0])
28         {
29             for(int i=0;i<26;i++) if((d&(1<<i))==0 && q[i].size())
30             {
31                 auto it=lower_bound(q[i].begin(),q[i].end(),id);
32                 if(it!=q[i].end())
33                 {
34                     if((d|a[*it])==a[0])
35                     {
36                         ans[an++]=i+'a';
37                         d|=1<<i;
38                         id=*it;
39                         break;
40                     }
41                 }
42             }
43         }
44         ans[an]=0;
45         puts(ans);
46     }
47 //  printf("time=%.3lf
",(double)clock()/CLOCKS_PER_SEC);
48     return 0;
49 }
solve.cpp

题解:

用一个int的bit表示每个字母是否存在,设字母集合为U,从后往前扫一遍算出存在后缀和,即a[i]表示这个数后面有哪些字母
再从前往后扫一遍,记录已有字母的集合U1,对于位置i,每次取能与U1,a[i]并起来能得到全集U 的最小的字母,最后字母集合U1为所求结果

原文地址:https://www.cnblogs.com/cdyboke/p/7010503.html