给出
个字符串,要求选出其中一些串按顺序拼接成一个长度为
的串,并且要求拼接串的字典序最小。
每个串长度不超过
,总长度不超过
.
设
表示最后
个串,能否组成长度为
的字符串.
背包转移即可,可以用bitset优化
用队列记录到当前位置的合法串的位置
每次贪心的选取字典序最小的字符,并且把那些当前非最小的状态删去,将依然合法的状态的下一个位置加入队列。
如果某个串走到底了,就枚举它后面所有串看是否合法,能就加入队列。
这里有一个限制队列元素的剪枝,应该是可以卡的,但是数据不是很刁钻,就AC了…
#include<bits/stdc++.h>
#define LL long long
#define clr(x,i) memset(x,i,sizeof(x))
using namespace std;
const int N=2011;
#define pii pair<int,int>
#define x first
#define y second
int n,K,len[N];
bitset<N*5> ok[N];
string s[N],ans;
pii f[2][N*20];
int main()
{
ios::sync_with_stdio(0);
cin>>n>>K;
for(int i=1;i<=n;i++){
cin>>s[i];
len[i]=s[i].size();
}
ok[n+1][0]=1;
for(int i=n;i>0;i--){
ok[i]=ok[i+1]|(ok[i+1]<<len[i]);
// cout<<i<<' ';
// for(int j=0;j<=K;j++){
// ok[i][j]|=ok[i+1][j];
// if(j+len[i]<=K)ok[i][j+len[i]]|=ok[i+1][j];
// printf("%d ",ok[i][j]);
// }
// cout<<endl;
}
int qcnt=0,tcnt=0;
for(int i=1;i<=n;i++)
if(ok[i+1][K-len[i]])
f[1][++qcnt]=pii(i,0);
for(int t=1;t<=K;t++)
{
int i=t&1;
// cout<<' '<<i<<endl;
qcnt=min(qcnt,K*2);
// cout<<qcnt<<" ";
char ch='z';
for(int j=1;j<=qcnt;j++)
ch=min(ch,s[f[i][j].x][f[i][j].y]);//cout<<f[i][j].x<<' '<<f[i][j].y<<" ";
// cout<<endl;
ans.push_back(ch);
int head=n+1;
for(int j=1;j<=qcnt;j++)
{
if(s[f[i][j].x][f[i][j].y]!=ch) continue;
if(f[i][j].y==len[f[i][j].x]-1)
head=min(head,f[i][j].x);
else
f[i^1][++tcnt]=pii(f[i][j].x,f[i][j].y+1);
}
// cout<<head<<endl;
for(int j=head+1;j<=n;j++)
if(K-t-len[j]>=0&&ok[j+1][K-t-len[j]])
f[i^1][++tcnt]=pii(j,0);
qcnt=tcnt; tcnt=0;
}
cout<<ans<<endl;
return 0;
}