ztr loves substring
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 299 Accepted Submission(s): 164
Problem Description
ztr love reserach substring.Today ,he has n string.Now ztr want to konw,can he take out exactly k palindrome from all substring of these n string,and thrn sum of length of these k substring is L.
for example string "yjqqaq"
this string contains plalindromes:"y","j","q","a","q","qq","qaq".
so we can choose "qq" and "qaq".
for example string "yjqqaq"
this string contains plalindromes:"y","j","q","a","q","qq","qaq".
so we can choose "qq" and "qaq".
Input
The first line of input contains an positive integer
T(T<=10)
indicating the number of test cases.
For each test case:
First line contains these positive integer N(1<=N<=100),K(1<=K<=100),L(L<=100) .
The next N line,each line contains a string only contains lowercase.Guarantee even length of string won't more than L.
For each test case:
First line contains these positive integer N(1<=N<=100),K(1<=K<=100),L(L<=100) .
The next N line,each line contains a string only contains lowercase.Guarantee even length of string won't more than L.
Output
For each test,Output a line.If can output "True",else output "False".
Sample Input
3 2 3 7 yjqqaq claris 2 2 7 popoqqq fwwf 1 3 3 aaa
Sample Output
False True True
Source
解题报告:
典型的背包问题,适当变种,并需要做一些优化,否则会超时。dp[i][j]是一个set,用于表示扫描到第i个包时,当前总量正好达到j时,每种装包方案的装包个数。因此dp[i][j]的集合就是dp[i-1][j-a[j]]的集合元素每个值+1。注意做好初始化,另外当前包的状态只与前一个状态有关,因此可以状态压缩,每次内循环从后向前扫描即可。重量为x的包最多只需要L/x+1个包就能装好,所以可以优化,否则请试试一百个字符且L为100时耗时多少。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
using namespace std;
#define max(x, y) ((x) > (y) ? (x) : (y))
#define min(x, y) ((x) < (y) ? (x) : (y))
#define maxn 500010
int a[maxn];
#define maxl 105
set<int> dp[maxl];
int b[maxl]; /// 优化,记录每个长度的个数
typedef set<int>::iterator siter;
int N, K, L;
int ct;
void CountPar(const char sz[])
{
int len = strlen(sz);
for (int i = 0; i < len; ++i)
{
// mid
for (int j = 0; i - j >= 0 && i + j < len && 2 * j + 1 <= L; ++j)
{
if (sz[i-j] == sz[i+j])
{
//a[ct++] = 2 * j + 1;
++b[2*j+1];
}
else
break;
}
// right
for (int j = 0; i - j >= 0 && i + j + 1< len && 2 * (j + 1) <= L; ++j)
{
if (sz[i-j] == sz[i+j+1])
{
//a[ct++] = 2 * (j + 1);
++b[2*(j+1)];
}
else
break;
}
}
}
void Solve()
{
dp[0].insert(0);
dp[a[0]].insert(1);
for (int i = 1; i < ct; ++i)
{
for (int j = L; j >= 0; --j)
{
int preSum = j - a[i];
if (preSum < 0) continue;
for (siter it = dp[preSum].begin(); it != dp[preSum].end(); ++it)
{
int tmp = (*it) + 1;
dp[j].insert((*it) + 1);
if (j == L && tmp == K)
{
printf("True\n");
return;
}
}
}
}
for (siter it = dp[L].begin(); it != dp[L].end(); ++it)
{
if (*it == K)
{
printf("True\n");
return;
}
}
printf("False\n");
}
int main()
{
//freopen("input.txt", "r", stdin);
int cas;
scanf("%d", &cas);
for (int i = 1; i <= cas; ++i)
{
scanf("%d %d %d", &N, &K, &L);
ct = 0;
for (int i = 0; i < L; ++i)
{
dp[i].clear();
}
memset(b, 0, sizeof(b));
char sz[maxl] = {0};
for (int i = 0; i < N; ++i)
{
scanf("%s", sz);
CountPar(sz);
}
// 优化
for (int i = 1; i <= L; ++i)
{
for (int j = 1; j <= b[i] && j * i <= L; ++j)
{
a[ct++] = i;
}
}
Solve();
}
return 0;
}