HDU 5677 ztr loves substring

Manacher+二维费用多重背包 二进制优化

这题是一眼标算....先计算出每个长度的回文串有几种,然后用二维费用的多重背包判断是否有解。

多重背包做的时候需要二进制优化。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

const int maxn = 300;
int N, p[maxn];
char str[maxn], b[maxn];
int cnt[maxn];
int n, k, L;
bool dp[maxn][maxn];

void init()
{
    int i;
    for (i = 0; str[i]; i++) b[2 * i + 1] = '#', b[2 * i + 2] = str[i];
    N = 2 * i + 1;
    b[0] = '$', b[N] = b[N + 1] = '#';
}

void solve()
{
    int i, id, max = 0;
    for (i = 1; i <= N; i++)
    {
        p[i] = i < max ? std::min(max - i, p[2 * id - i]) : 1;
        while (b[i + p[i]] == b[i - p[i]]) ++p[i];
        if (i + p[i] > max) max = i + p[i], id = i;
        cnt[p[i] - 1]++;
    }
}
int main()
{
    int T; scanf("%d", &T);
    while (T--)
    {
        memset(dp, 0, sizeof dp); dp[0][0] = 1;
        memset(cnt, 0, sizeof cnt);
        scanf("%d%d%d", &n, &k, &L);
        while (n--){ scanf("%s", str); init(); solve(); }
        for (int i = 100; i >= 1; i--) 
            cnt[i] = cnt[i] + cnt[i + 2];
        for (int i = 100; i >= 1; i--)
        {
            if (cnt[i] == 0) continue;
            int val = i, num = cnt[i];
            int t = 1;
            while (num)
            {
                if (num > t)
                {
                    int tmp_val = val*t;
                    for (int d = L; d >= 0; d--)
                    {
                        for (int f = k; f >= 0; f--)
                        {
                            if (dp[d][f] == 0) continue;
                            if (d + tmp_val <= L&&f + t <= k)
                                dp[d + tmp_val][f + t] = 1;
                        }
                    }
                    num = num - t;
                    t = t * 2;
                }
                else
                {
                    int tmp_val = val*num; 
                    for (int d = L; d >= 0; d--)
                    {
                        for (int f = k; f >= 0; f--)
                        {
                            if (dp[d][f] == 0) continue;
                            if (d + tmp_val <= L&&f + num <= k)
                                dp[d + tmp_val][f + num] = 1;
                        }
                    }
                    num = 0;
                }
            }
        }
        if (dp[L][k]) printf("True\n");
        else printf("False\n");
    }
    return 0;
}

 

posted @ 2016-05-01 14:36  Fighting_Heart  阅读(208)  评论(0编辑  收藏  举报