EOJ:Ugly Numbers

——给一串数字。要求在数字中(第一个数字前不能添加)添加“+”或者“-”使得最后算出来的结果能够被2,3,5,7其中的一个整除。求这样的添加方案共有多少种。

——DP

——http://202.120.106.94/onlinejudge/problemshow.php?pro_id=426

——————————————————————————————————————————————————————————

拿到题首先的想法是搜索……一看这个复杂度果断就放弃了。

在做DP之前有个很重要的想法就是对结果取余,直接保存余数即可。

对几取余?

直观的想法是对2,3,5,7以及两两,三三,四个的公倍数分别取余,然后用容斥原理来做

但是仔细一想,只需要对210取余即可。最后的结果即为余数是0,2,4,6,8,……和3,6,9,12……5,10,15……7,14,21……这些相加

这样是不会有重复计算的,因为被210除余2和被210除余6的数肯定不是一个数。

——————————————————————————————————————————————————————————

首先因为添加的是加减号而没有乘除,所以不需要考虑优先级的问题,因此可以从左往右直接DP。

——————————————————————————————————————————————————————

之前想到的一个错误的DP方程:

DP[i][j]=Segma{DP[i-1][(j-str[i])%210]+DP[i-1][(j+str[i])%210]+DP[i-1][(j*10+str[i])%210]} 

简单说就是一位一位的做,每一位可以添加加号减号或者不添加符号。

问题出在不添加符号,如果第I位之前的结果是31的话,在第I-1位与第I位之间不添加符号,按上面方程就是31*10+STR[I],但实际上31可能是由20+11得来的。那么不填符号应该是20+11*10+STR[I]才对。

——————————————————————————————————————————————————————————————————

正确的转移方程:

DP[I][J]表示字符串从0到I-1为止,这么多个数字添加了符号以后被210除余J的方案数。

X为从K到I-1字符串中的数字的值。

DP[I][J]=Segma{DP[K][J-X]+DP[K][J+X]}        0<=K<I

J-X就是添加了负号,J+X添加的是正号

#include<stdio.h>
#include<string.h>
#define SIZE 45
long long dp[SIZE][210];
bool flag[210];
long long ans;
int len, n;
char str[SIZE];
void solve()
{
	int i, j;
	long long k, tmp;
	memset(dp, 0, sizeof(dp));
	dp[0][0] = 1;
	for (i = 1; i <= len; i++)
		for (j = 0; j < i; j++)
		{
			tmp = 0;
			for (k = j; k < i; k++)
				tmp = (tmp * 10 + str[k] - '0') % 210;
			for (k = 0; k < 210; k++)
			{
				dp[i][(k + tmp) % 210] += dp[j][k];
				if (j)
					dp[i][(k - tmp + 210) % 210] += dp[j][k];
			}
		}
	memset(flag, 0, sizeof(flag));
	for (i = 0; i < 210; i += 2)
		flag[i] = true;
	for (i = 0; i < 210; i += 3)
		flag[i] = true;
	for (i = 0; i < 210; i += 5)
		flag[i] = true;
	for (i = 0; i < 210; i += 7)
		flag[i] = true;
	ans = 0;
	for (i = 0; i < 210; i++)
		if (flag[i])
			ans += dp[len][i];
}
int main()
{
	int i;
	scanf("%d", &n);
	getchar();
	for (i = 0; i < n; i++)
	{
		scanf("%s", str);
		len = strlen(str);
		solve();
		printf("Case #%d: %lld\n", i + 1, ans);
	}
	return 0;
}

  

posted on 2011-07-25 22:52  风也轻云也淡  阅读(149)  评论(0编辑  收藏  举报