题目链接: http://codeforces.com/contest/1009/problem/G
题意:
给你字母 ′ a ′ − ′ f ′ 'a'-'f' ′a′−′f′ 的个数,现在给你 m m m 个条件,每个条件要求,位置 p o s pos pos 上可以放的合法字符集 S S S ,现在要你求合法的最小字典序的字符串(如果不存在输出“不可能”)。
做法:
枚举从小到大的字母肯定是跑不了了,但是枚举之后的验证就很重要了。
一直错的原因就是因为没弄明白内核,先说为什么错,可能蛮多人和我一样原来弄不懂的。开始的时候我把所谓的 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示成了,从位置 i − n i-n i−n 中有多少个状态 j j j ,这样的话在后面就能做处理了,当要求的数字个数不满足要求的时候,那么就不能放当前的字母。
但是这样想其实是不对的,比如说。举个栗子:
a
b
f
f
f
c
abfffc
abfffc
6
6
6
1
1
1
d
f
df
df
2
2
2
a
f
af
af
3
3
3
a
c
ac
ac
4
4
4
a
b
ab
ab
5
5
5
b
b
b
6
6
6
b
d
f
bdf
bdf
答案是
f
f
c
a
b
f
ffcabf
ffcabf
在第二个字母放下的时候,因为后面当中的状态 a b ab ab 只需要一个 b b b 合法,状态 b b b 也是需要一个 b b b 合法,但是如果我把 a a a 放在这里,这两个就不能同时满足条件了。即后面每个状态满足,也不能保证值一定是够用的。
然后就要引入这个Hall定理。
二部图G中的两部分顶点组成的集合分别为X, Y. X = X 1 , X 2 , X 3 , X 4 , . . . . . . . . . , X m , Y = Y 1 , Y 2 , Y 3 , Y 4 , . . . . . . . . . , Y n X={X_1, X_2, X_3,X_4,.........,X_m}, Y={Y_1, Y_2, Y_3, Y_4 ,.........,Y_n} X=X1,X2,X3,X4,.........,Xm,Y=Y1,Y2,Y3,Y4,.........,Yn ,G中有一组无公共点的边,一端恰好为组成X的点的充分必要条件是:
X中的任意k个点至少与Y中的k个点相邻。 ( 1 ≤ k ≤ m ) (1≤k≤m) (1≤k≤m)
在这里的体现就是,对于任意一种状态 S S S 里的字母 ,都要有超过其要求字母的数量存在,这样才能使得在最后所有的状态都能满足合法的条件。 即在上面的 X X X 都被满足。
代码
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=100005;
const int N=(1<<6);
char s[maxn],op[10],ans[maxn];
int n,m,las[maxn][N+1];
int nu[10],val[maxn];
int main(){
scanf("%s%d",s+1,&m);
n=strlen(s+1);
for(int i=1;i<=n;i++){
nu[s[i]-'a']++;
}
rep(i,1,m){
int p; scanf("%d%s",&p,op);
for(int j=0;j<strlen(op);j++){
int a=op[j]-'a';
val[p]|=(1<<a);
}
}
for(int i=n;i>=1;i--){
if(val[i]==0) val[i]=N-1;
for(int j=0;j<N;j++){
las[i][j]=las[i+1][j];
if(j&val[i]) las[i][j]++;
}
}
int flag=0;
for(int i=1;i<=n;i++){
int ok=0;
for(int j=0;j<6;j++){
if((val[i]&(1<<j))==0||nu[j]==0) continue;
nu[j]--;
int can=1;
for(int k=1;k<N;k++){
int tmp=0;
for(int p=0;p<6;p++){
if((k&(1<<p))==0) continue;
tmp+=nu[p];
}
if(tmp>las[i+1][k]) can=0;
}
if(can){
ans[i]='a'+j;
ok=1;
break;
}
nu[j]++;
}
if(!ok){
flag=1; break;
}
}
if(flag) printf("Impossible\n");
else {
rep(i,1,n){
printf("%c",ans[i]);
}
printf("\n");
}
return 0;
}