CF1009G Allowed Letters

link

 

题意:

给你一个长为n的串,字符集'a'~'f'。你可以重排这个串,满足指定m个位置上只能放特定的字符,m个位置以及字符集会给出。求字典序最小的串?

$n,m\leq 10^5.$

 

题解:

稍微需要那么一点技巧的贪心。

贪心策略比较显然,无非就是从左往右放尽可能小的字符,同时保证当前位置之后有合法解。

考虑预处理a[i]:i位置可以放的字符集;cnt[i]:集合i的字符在整个串中出现的次数;b[i][j]:i~n位置中a[]被集合j包含的个数。每次判断一个字符是否可行,只要枚举任意一个集合j,如果j集合中所有可用的字符在之后每个放一个位置还不够的话,说明不合法。

依次贪心下去即可。

复杂度$\mathcal{O}(6\times 2^6\times n)$。

 

code:

 1 #include<bits/stdc++.h>
 2 #define rep(i,x,y) for (int i=(x);i<=(y);i++)
 3 #define per(i,x,y) for (int i=(x);i>=(y);i--)
 4 #define ll long long
 5 #define inf 1000000001
 6 #define y1 y1___
 7 using namespace std;
 8 ll read(){
 9     char ch=getchar();ll x=0;int op=1;
10     for (;!isdigit(ch);ch=getchar()) if (ch=='-') op=-1;
11     for (;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
12     return x*op;
13 }
14 #define N 100005
15 #define M 70
16 int n,m,a[N],b[N][M],tmp[M],cnt[M];char s[N],s2[N],ans[N];
17 int main(){
18     scanf("%s",s+1);n=strlen(s+1);
19     m=read();
20     while (m--){
21         int k=read(),l;scanf("%s",s2+1);l=strlen(s2+1);
22         rep (i,1,l) a[k]|=1<<s2[i]-'a';//该位置可以放的字符集
23     }
24     rep (i,1,n) if (!a[i]) a[i]=(1<<6)-1;
25     rep (i,1,n){
26         int x=s[i]-'a';
27         rep (j,0,(1<<6)-1) if (j>>x&1) cnt[j]++;//cnt[i]:集合i的字符在整个串中出现的次数
28     }
29     per (i,n,1) rep (j,0,(1<<6)-1){//b[i][j]:i~n位置中a[]被集合j包含的个数
30         if ((j&a[i])==a[i]) tmp[j]++;
31         b[i][j]=tmp[j];
32     }
33     rep (p,1,n-1){
34         bool flag=0;
35         rep (i,0,5) if (cnt[1<<i]&&(a[p]>>i&1)){//贪心,保证之后还能放
36             bool chk=1;
37             rep (j,0,(1<<6)-1) if (cnt[j]-(j>>i&1)<b[p+1][j]){//j集合中每个字符放一个位置还不够,不合法
38                 chk=0;
39                 break;
40             }
41             if (chk){
42                 flag=1;ans[p]=i+'a';
43                 rep (j,0,(1<<6)-1) if (j>>i&1) cnt[j]--;
44             }
45         }
46         if (!flag){puts("Impossible");exit(0);}
47     }
48     bool flag=0;
49     rep (i,0,5) if (cnt[1<<i]&&(a[n]>>i&1)){
50         flag=1;ans[n]=i+'a';
51         break;
52     }
53     if (!flag){puts("Impossible");exit(0);}
54     ans[n+1]='\0';
55     puts(ans+1);
56     return 0;
57 }
View Code

 

posted @ 2018-07-15 14:29  bestfy  阅读(436)  评论(0编辑  收藏  举报