码迷,mamicode.com
首页 > 其他好文 > 详细

CF1009G Allowed Letters

时间:2018-07-15 16:11:18      阅读:157      评论:0      收藏:0      [点我收藏+]

标签:ret   com   put   main   ==   依次   let   close   tle   

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

 

CF1009G Allowed Letters

标签:ret   com   put   main   ==   依次   let   close   tle   

原文地址:https://www.cnblogs.com/bestFy/p/9313500.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!