HDU 3652 B-number

题意:

1..n的数中数字包含‘13’且能被13整除的,有多少个。n<10^9

分析:

按位DP

困在能被13整除上了,查了能被13整除的数的特性,不知道怎么转化dp...

后来看了解题报告,状态上多记录个模13的余数就好了~


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int ans;
int num[10], ln;
int f[10][13][3];

void NtoNum(int *num, int &ln, int n){
	ln = 0;
	while(n){
		num[++ln] = n % 10;
		n = n / 10;
	}
}

int dfs(int cur, int pre, int mod, bool apr, bool flag){
	int i, ret, high;
	if (cur <= 0)	return apr && mod == 0;
	if (!flag && apr && ~f[cur][mod][2]) return f[cur][mod][2];
	if (!flag && !apr && pre != 1 && ~f[cur][mod][1]) return f[cur][mod][1];
	if (!flag && !apr && pre == 1 && ~f[cur][mod][0]) return f[cur][mod][0];
	
	high = flag ? num[cur] : 9;
	ret = 0;
	for (i = 0; i <= high; i++){
		ret += dfs(cur - 1, i, (mod * 10 + i) % 13, apr || (pre == 1 && i == 3), flag && (i == high));
	}
	if (!flag){
		if (pre == 1 && !apr) f[cur][mod][0] = ret;
		if (pre != 1 && !apr) f[cur][mod][1] = ret;
		if (apr) f[cur][mod][2] = ret;
	}
	return ret;
}

int main(){
	int n;
	while(scanf("%d",&n) != EOF){
		ans = 0;
		NtoNum(num, ln, n);
		memset(f, 0xff, sizeof(f));
		ans = dfs(ln, 0, 0, false, true);
		printf("%d\n", ans);
	}
	return 0;
}

/*
f[i][k][0] 不含13,不以1结尾
f[i][k][1] 不含13,以1结尾
f[i][k][2] 含13

f[i + 1][(k * 10 + num) % 13][0] += f[i][k][0], num != 1
f[i + 1][(k * 10 + 1) % 13][0] += f[i][k][1], num != 1, 3
f[i + 1][(k * 10 + 1) % 13][1] += f[i][k][0] + f[i][k][1]
f[i + 1][(k * 10 + num) % 13][2] += f[i][k][2]
f[i + 1][(k * 10 + 3) % 13][2] += f[i][k][1]
其实又用记忆化搜索实现的。。。1A哦~写完就A了的哦~哈哈~~
还是记忆化搜索实现简单。。。
总结经验,记录dfs时,不一定要开和参数一样的数组,
适当变换下,分成几种情况开多个数组,可以节省下内存
46ms 196k
就是慢点...
*/


你可能感兴趣的:(HDU 3652 B-number)