Uva1633_分阶段dp、状态dp

动态规划训练3——Uva1633

                   Dyslexic Gollum
  ‘Light, light of Sun and Moon, he still feared and hated, and he always will, I think; but
he was cunning. He found he could hide from daylight and moonshine, and make his way
swiftly and softly by dead of night with his pale cold eyes, and catch small frightened or
unwary things. He grew stronger and bolder with new food and new air. He found his way
into Mirkwood, as one would expect.’

Gandalf, describing Gollum after he ventured forth from Moria.
Gollum has spent half a millennium in the long darkness of Moria, where his eyes grew used to the
dark, and without caring for reading or writing, he became dyslexic. Indeed, as much as he hates the
Moon and the Sun, he also hates strings with long palindromes in them.
Gollum has a tolerance level of K, which means that he can read a word so long as it does not
contain any palindromic substring of length K or more. Given the values N and K, return how many
BINARY strings of length N can Gollum tolerate reading.
Input
The rst line contains T, the number of test cases.
Each test case consists of one line containing 2 integers, N and K.
Output
For each test case, output the answer modulo 1,000,000,007.
Constraints:
1 T 100
1 N 400
1 K 10
Notes/Explanation of Sample Input:
For the rst test case, 01 and 10 are the valid binary strings, while 00 and 11 are invalid.
For the second test case, 001, 011, 100, 110 are the valid binary strings.
For the third test case, all possible binary strings of length 3 are valid.
Sample Input
3
2 2
3 3
3 4
Sample Output
2
4
8

  读完本题较容易想到分阶段的dp:每个阶段在字符串末尾添上0或1。所以可设置一个状态变量i表示当前字符串的长度。
   此题要求字符串中回文串的长度小于k,则我们规定每个阶段得到的字符串中回文串最长为k-1。据此规则,我们可以得到,每个阶段引入的字符至多导致长度k+1的回文串,表明引入的字符至多对末尾长度为k+1的串产生影响。由此我们可再引入一个状态量j,记录末尾k+1位串的二进制状态。再由此题给出k<=10,为了方便,我们取j最大2^11-1。
  综上,最终我们的状态设置为(字符串长度i,字符串最后11位j),数据范围满足要求。
  有关状态转移:(j中二进制低位表示字符串末位)
   当j中回文串长度大于等于k时,
    dp[i][j]=0;
   否则,
    dp[i][j]=dp[i-1][j>>1]+dp[i-1][(j>>1)+(1<<10)];
  有关实现细节:
   本题要判断j中回文串的长度,因此可用二维数组记录长度小于12的二进制数中回文串的长度。
   可用简单的动态规划快速实现。
   同时,这样还可直接得到i<=11时,dp[i][j]的值。只需对i>11时进行转移。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include <math.h>
#include <algorithm>
using namespace std;
const int BASE = 1e9 + 7;
int pali[15][3000] = { 0 }, dp[15][405][3000] = { 0 };
int main(void) {
	pali[1][0] = pali[1][1] = pali[2][1] = pali[2][2] = 1;
	pali[2][0] = pali[2][3] = 2;
	for (int i = 3; i <= 11; ++i)
		for (int j = 0, t1, t2; j <= (1 << i) - 1; ++j) {
			t1 = 1 & j, t2 = j >> (i - 1);
			if (t1 == t2 && pali[i - 2][(j&((1 << (i - 1)) - 1)) >> 1] == i - 2) pali[i][j] = i;
			else pali[i][j] = max(pali[i - 1][j >> 1], pali[i - 1][j&((1 << (i - 1)) - 1)]);
		}
	for (int k = 2; k <= 10; ++k)
		for (int n = 1; n <= 11; ++n)
			for (int j = 0; j <= (1 << n) - 1; ++j)
				if (pali[n][j] < k) dp[k][n][j] = 1;
	for (int k = 2; k <= 10; ++k)
		for (int n = 12; n <= 400; ++n)
			for (int j = 0; j <= (1 << 11) - 1; ++j)
				if (pali[11][j] >= k) dp[k][n][j] = 0;
				else dp[k][n][j] = (dp[k][n - 1][j >> 1] + dp[k][n - 1][(j >> 1) + (1 << 10)])%BASE;
	int T, N, K;
	scanf("%d", &T);
	while (T--) {
		scanf("%d%d", &N, &K);
		int	ans = 0;
		int n = min(11, N);
		for (int i = 0; i <= (1 << n) - 1; ++i)
			ans = (ans + dp[K][N][i]) % BASE;
		cout << ans << endl;
	}
	//system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值