hihoCoder 1033 : 交错和 数位dp

             思路:数位dp,dp(i, j, k)表示考虑i位数,每位数可以任意取[0~9],并且这i位数的交错和为j,k=1表示前缀全是0(如000456),k=0表示前缀不为0。注意,前缀是否为0是这道题的一大坑点。在计算交错和的过程中可能会出现负数,这时应该加上一个数让它变成非负整数。f(123) = f(1) - f(23),根据这个来进行状态转移。

AC代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000") 
#define eps 1e-10
#define inf 0x3f3f3f3f
#define PI pair 
typedef long long LL;
const int maxn = 400 + 5;
const int Non = 200, mod = 1e9+7; 
LL dp[20][maxn][2], cnt[20][maxn][2];
int b[25];
int k;
PI dfs(int pre, int d, int flag, int u, int pre_zero) {
	if(d == 0) {
		if(pre == k) return make_pair(0, 1);
		else return make_pair(0, 0);
	} 
	int w = (k-pre)/u + Non;
	if(!flag && dp[d][w][pre_zero] != -1) 
		return make_pair(dp[d][w][pre_zero], cnt[d][w][pre_zero]);
	int up = flag ? b[d] : 9;
	LL x = 0, y = 0;
	for(int i = 0; i <= up; ++i) {
		PI pi;
		if(pre_zero) {
			if(i == 0) pi = dfs(0, d-1, flag&(i==up), 1, 1);
			else pi = dfs(i, d-1, flag&(i==up), -1, 0);
		}
		else pi = dfs(pre + u*i, d-1, flag&(i==up), -u, 0);
		//用tmp防止溢出 
		LL tmp = pi.second * i % mod;
		tmp *= ((LL)pow(10, d-1))%mod;
		x += tmp + pi.first;
		x %= mod;
		y += pi.second;
		y %= mod;
	} 
	if(!flag) {
		dp[d][w][pre_zero] = x;
		cnt[d][w][pre_zero] = y;
	}
	return make_pair(x, y);
}

int getBit(LL x) {
	int cur = 1;
	while(x) {
		b[cur++] = (int)(x%10);
		x /= 10;
	}
	return cur-1;
 }
 
LL solve(LL x) {
	if(x <= 0) return 0;
	int n = getBit(x);
	PI ans = dfs(0, n, 1, 1, 1);
	return ans.first; 
}

int main() {
	memset(dp, -1, sizeof(dp));
	memset(cnt, 0, sizeof(cnt));
	LL l, r;
	while(scanf("%lld%lld%d", &l, &r, &k) == 3) {
		LL a =  solve(r), b = solve(l-1);
		printf("%lld\n", (a-b+mod)%mod);
	}
	return 0;
}

如有不当之处欢迎指出!

你可能感兴趣的:(算法之路)