这是一场BC里的题,虽然这套题非常辣鸡,但这题对我来说还是有学习价值的。
首先是暴力跑一下,统计一下不同长度的回文串分别有多少个,然后就是跑存在性的多重背包了,二进制思想不错!
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <string.h>
#include <memory.h>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#define ll long long
char str[111];
int cnt[111];
bool dp[111][111];
int main(){
int T;
cin>>T;
while(T--){
memset(cnt,0,sizeof(cnt));
int N,K,L;
cin>>N>>K>>L;
for(int i=1;i<=N;i++){
scanf("%s",str);
int len = strlen(str);
//odd
for(int i=0;i<len;i++){
int l = 0;
for(int l=0;;l++){
if(i-l<0 || i+l==len){
break;
}
if(str[i-l]==str[i+l]){
cnt[l*2+1]++;
}else{
break;
}
}
}
//even
for(int i=0;i<len-1;i++){
int l = 0;
for(int l=0;;l++){
if(i-l<0 || i+l+1==len){
break;
}
if(str[i-l]==str[i+l+1]){
cnt[l*2+2]++;
}else{
break;
}
}
}
}
//dp数组: 用了几个串 当前长度 的可达性
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for(int i=1;i<=100;i++){
if(dp[K][L]){
break;
}
//二进制拆解
int num = cnt[i];
int kk = 1;
if(!num)continue;
while(kk < num){
for(int j=K;j>=kk;j--){
for(int k=L;k>=i*kk;k--){
if(dp[j-kk][k-i*kk]){
dp[j][k] = 1;
}
}
}
num -= kk;
kk<<=1;
}
if(!num)continue;
for(int j=K;j>=num;j--){
for(int k=L;k>=i*num;k--){
if(dp[j-num][k-i*num]){
dp[j][k] = 1;
}
}
}
}
if(dp[K][L]){
printf("True\n");
}else{
printf("False\n");
}
}
return 0;
}