hdu 5677-ztr loves substring

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".
 

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.
 

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值