您的位置:首页 > 其它

uva11361(数论DP)

2015-07-25 08:36 246 查看
题意:

基本是看了大白上的思路,然后还参考了http://blog.csdn.net/lenleaves/article/details/9104417

统计大于等于a,小于等于b,每一位之和可以被k整除,且本身也能被k整除的数的数量。

用f(d,m1,m2)表示剩余d个数字,这d个数字之和模k为m1,这d个数字组成的整数倍k整除之后余m2, 这样的数字的数量,

求a与b之间这样数字的数量,我们转化问题为前缀和只差即 sum(b)-sum(a-1) (具体求解过程的不同,此处可能会有小出入)。

状态方程 训练指南上面有一个小错误。

正确的状态方程应为

f(d,m1,m2)=sum{ f( d-1,(m1-x) mod k,(m2-x*10^(d-1)) mod k ) |x=0,1,2.......9}

注意当我们将星号限制在后面三位的时候,我第四位的枚举范围,应在原本第四位的范围之内。而之后的枚举过程中,由于第四位小于原本的第四位,所以低位可以从0枚举到9

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>

using namespace std;

int a,b,k;
int dp[15][110][110];
int pw[11]={1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };

int dfs(int d,int m1,int m2) {
if(d == 0)
return (m1 == 0 && m2 == 0) ? 1 : 0;
if(dp[d][m1][m2] >= 0)
return dp[d][m1][m2];
dp[d][m1][m2]=0;
for(int i = 0; i < 10; i++)
dp[d][m1][m2] += dfs(d - 1, ((m1 - i) % k + k) % k, ((m2 - i * pw[d-1]) % k + k) % k);
return dp[d][m1][m2];
}

int func(int n) {
int d = 0, m1 = 0, m2 = 0, a[15];
if(n ==0)
a[d++] = 0;
while(n != 0) {
a[d] = n % 10;
n /= 10;
d++;
}
int ans=0;
for(int i = d - 1; i >= 0; i--) {
if(i!=0)
for(int j=0;j<a[i];j++) {
ans += dfs(i,(k-(m1+j)%k)%k,(k-(m2+pw[i]*j)%k)%k);
}
else
for(int j = 0; j <=a[i]; j++) {
ans+=dfs(i,(k-(m1+j)%k)%k,(k-(m2+pw[i]*j)%k)%k);
}
m1 += a[i];
m2 += pw[i] * a[i];

}
return ans;
}

int main() {
int t;
scanf("%d", &t);
while(t--) {
scanf("%d%d%d", &a, &b, &k);
if(k > 85)
printf("0\n");
else {
memset(dp,-1,sizeof(dp));
printf("%d\n",func(b)-func(a-1));
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: