HDU 5677 ztr loves substring(Manacher+dp+二进制分解)

题目链接:HDU 5677 ztr loves substring

题意:有n个字符串,任选k个回文子串,问其长度之和能否等于L。

题解:用manacher算法求出所有回文子串的长度,并记录各长度回文子串的个数,再用背包思想判断是否有解。

dp[i][j]:选取i个回文子串,长度之和是否为j

其中用到二进制分解思想,将回文串长为i的数量cnt[i]拆成1+2+4+8+…形式,进行优化。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 #define CLR(a,b) memset((a),(b),sizeof((a)))
 6 const int N = 105;
 7 int dp[N][N], w[N*N*N], cnt[N], cnt1[N*N*N];
 8 char s[N*2];
 9 void Manacher(char s[],int len) {
10     char Ma[N*2];
11     int Mp[N*2] , l = 0;
12     CLR(Mp, 0);
13     Ma[l++] = '$';  Ma[l++] = '#';
14     for(int i = 0; i < len; i++) {
15         Ma[l++] = s[i];  Ma[l++] = '#';
16     }
17     int mx = 0, id = 0;
18     for(int i = 0;i < l; i++) {
19         Mp[i] = mx > i ? min(Mp[2*id-i], mx-i) : 1;
20         while(Ma[i+Mp[i]] == Ma[i-Mp[i]]) Mp[i]++;
21         if(i + Mp[i] > mx) {
22             id = i;
23             mx = i + Mp[i];
24         }
25         if(Ma[i] == '#'&& Mp[i] == 1) continue;
26         cnt[Mp[i]-1]++;//记录该回文串长度数量
27     }
28 }
29 int main(){
30     int t, i, j, n, k, l, x, num;
31     scanf("%d", &t);
32     while(t--) {
33         scanf("%d%d%d", &n, &k, &l);
34         CLR(dp, 0); CLR(cnt, 0);
35         for(i = 0; i < n; ++i) {
36             scanf("%s", s);
37             int len = strlen(s);
38             Manacher(s, len);
39         }
40         num = 0;
41         for(i = 1; i <= 100; ++i) {
42             for(j = 1; j <= cnt[i]; cnt[i] -= j, j <<= 1) {
43                 w[num] = j * i;
44                 cnt1[num++] = j;
45             }
46             if(cnt[i]) { w[num] = j * i; cnt1[num++] = j; }
47         }
48         dp[0][0] = 1;
49         for(i = 0; i < num; ++i)
50             for(j = l; j >= w[i]; --j)
51                 for(x = cnt1[i]; x <= k; ++x)
52                     dp[x][j] |= dp[x-cnt1[i]][j-w[i]];
53         if(dp[k][l]) puts("True");
54         else puts("False");
55     }
56     return 0;
57 }
0ms

 

posted @ 2017-02-05 22:59  GraceSkyer  阅读(183)  评论(1编辑  收藏  举报

~~~~~~ACM大牛语录,激励一下~~~~~~

为了世界的和平,为了女生的安全,我拼命做题,做题,做题!

用最短的时间,刷最多的题!

给我一滴泪,我就看到了你全部的海洋!

seize the hour, seize the day.

人生难免有无奈,幸福走远了,或是感叹幸福来迟了.其实我一直相信,无论手中的幸福是多么微不足道的感觉,我会把握住那每一分,每一秒,当幸福依旧像那百鸟般飞逝,终究无法掌握时,我会感谢它,曾经降临过!

A自己的题,让别人郁闷去吧

WA肠中过,AC心中留 TLE耳边过,AC特别牛

天然的悲苦和伤逝,过去有过,以后还会有

^*^一步一步往上爬^*^

AC就像练级,比赛就像PK. 练级不如PK好玩

其实,世上本没有ACM,AC的人多了,也便有了!

AC无止尽~ Seek you forever~

找呀找呀找水题,找到一个AC一个呀!

AC是检验程序的唯一标准。

真的猛士,敢于直面惨淡的人生,敢于正视淋漓的鲜血……