首页 > 代码库 > C - 字典序最小的子序列 51nod1255

C - 字典序最小的子序列 51nod1255

 

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\n",(double)clock()/CLOCKS_PER_SEC);48     return 0;49 }
solve.cpp

 

题解:

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

C - 字典序最小的子序列 51nod1255