UVa 11361 Investigating Div-Sum Property

这道题居然提交了十次才过....期间小问题不断。思路的话基本是《训练指南》里面来的,不过有几个小问题需要注意一下。第一,当K在大于100的情况下,就直接输出0就可以了。因为a,b不超过2^31,可以估算出a,b最多十位十进制数,那么每位最大为9,所以各个数字之和是不可能超过100的,那么个数字之和为模K为0的条件是永远不可能到达的。

还有一点是,当剩余数字d=0时,当且仅当m1和m2都为0时,即f[0][0][0]为1,其余f[0][][]都为0。然后将已知的f[d][m1][m2]保存下来,递归求解即可。最后,书上提到在计算(m2-b)%k时若b很大m2-b小于0时怎么办。我的解决方法是,凡是遇到减法,则用式子(m2-b%k+k)%k计算(没有翻过书,可能有更简单的方法)。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#define MAX 32+5
#define MAXK 100+5
using namespace std;

int f[MAX][MAXK][MAXK];
bool vis[MAX][MAXK][MAXK];
int T,k,A,B;
char temp[64];
int p[MAX];

int recur(int,int,int);

int main()
{
    //freopen("data.txt","r",stdin);
    cin>>T;
    f[0][0][0]=1;//d为0时,只有m1,m2都为0,才为1

    p[0]=1;
    for(int i=1;i<32;++i) p[i]=10*p[i-1];

    while(T--){
        cin>>A>>B>>k;
        if(k>100){//k>100结果必为0
            cout<<0<<endl;
            continue;
        }
        A--;
        sprintf(temp,"%d",A);//整数转化为字符串
        string a(temp);
        sprintf(temp,"%d",B);
        string b(temp);

        memset(vis,0,sizeof(vis));
        int ans,pos=ans=0;
        int m1,m2=m1=0;

        while(pos<b.size()){
            for(int i=0;i<b[pos]-'0';++i){
                ans+=recur(b.size()-1-pos,(m1-i%k+k)%k,(m2-i*p[10,b.size()-pos-1]%k+k)%k);
            }
            m1=(m1-(b[pos]-'0')%k+k)%k;
            m2=(m2-(b[pos]-'0')*p[10,b.size()-pos-1]%k+k)%k;
            pos++;
        }

        ans+=f[0][m1][m2];
        m1=m2=pos=0;

        while(pos<a.size()){
            for(int i=0;i<a[pos]-'0';++i){
                ans-=recur(a.size()-1-pos,(m1-i%k+k)%k,(m2-i*p[10,a.size()-pos-1]%k+k)%k);
            }
            m1=(m1-(a[pos]-'0')%k+k)%k;
            m2=(m2-(a[pos]-'0')*p[10,a.size()-pos-1]%k+k)%k;
            pos++;
        }
        ans-=f[0][m1][m2];

        cout<<ans<<endl;
    }

    return 0;
}

int recur(int d,int m1,int m2)
{
    if(vis[d][m1][m2]||d==0) return f[d][m1][m2];

    f[d][m1][m2]=0;
    for(int i=0;i<10;++i){
        f[d][m1][m2]+=recur(d-1,(m1+k-i%k)%k,(m2-i*p[10,d-1]%k+k)%k);
    }
    vis[d][m1][m2]=1;

    return f[d][m1][m2];
}
时间: 2024-10-30 01:21:20

UVa 11361 Investigating Div-Sum Property的相关文章

uva 11361 Investigating Div-Sum Property 数位dp

// uva 11361 Investigating Div-Sum Property 数位dp // // 题目大意: // // 给你一个整数a和一个整数b,问在[a,b]范围内,有多少个自身被k整除并且 // 各位数之和也能被k整除.比如k = 7 ,322满足条件,因为332能被整除7,并 // 3 + 2 + 2 = 7 也能被7整除 // // 解题思路: // // 求一个区间的题目,这类题目,往往可以转化为不超过x的f(x).则最后要求 // 的就是f(b) - f(a-1).如

UVA 11361 - Investigating Div-Sum Property(数位DP)

题目链接:11361 - Investigating Div-Sum Property 白书上的例题,不过没有代码,正好前几天写了一题数位DP的题目,这题也就相对轻松了. dp[i][x][y]表示加到第i位,数字 % k,数位和 % k的组合情况数,那么现在要添加一个0 - 9的数字上去状态转移为 dp[i + 1][(x * 10 + num) % k][(y + num) % k],计算总和后,由于数字本身不能超过最大值,所以最后还要添加上恰好前几位都为最大值的情况.然后最后在判断一下该数

【数位dp】UVA - 11361 - Investigating Div-Sum Property

经典数位dp!而且这好像是数位dp的套路板子--不需要讨论原来我很头疼的一些边界. 改天用这个板子重做一下原来的一些数位dp题目. http://blog.csdn.net/the_useless/article/details/53674906 题目大意: 给定a,b,k三个正整数,统计在[a,b]之间的整数n中,有多少n自身是k的倍数,且n的各个数字(十进制)之和也是k的倍数.(1?a?b?231) 题目分析: 这是一道典型的数位DP题. n非常大,若是直接枚举的话会超时,考虑利用加法原理计

uva 10891 Game of Sum (DP)

uva 10891 Game of Sum (DP) This is a two player game. Initially there are n integer numbers in an array and players A and B get chance to take them alternatively. Each player can take one or more numbers from the left or right end of the array but ca

UVa 11361 (计数 递推) Investigating Div-Sum Property

题意: 统计[a, b]中有多少个数字满足:自身是k的倍数,而且各个数字之和也是k的倍数. 分析: 详细分析见<训练之南>吧,=_=|| 书上提出了一个模板的概念,有了模板我们就可以分块计算. 虽然书上定义f(x)表示不超过x的非负整数且满足条件的个数,但为了编码方便,代码中f(x)的含义为0~x-1中满足条件的个数. 这样最终所求为f(b+1) - f(a) 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int MOD

09_Sum游戏(UVa 10891 Game of Sum)

问题来源:刘汝佳<算法竞赛入门经典--训练指南> P67 例题28: 问题描述:有一个长度为n的整数序列,两个游戏者A和B轮流取数,A先取,每次可以从左端或者右端取一个或多个数,但不能两端都取,所有数都被取完时游戏结束,然后统计每个人取走的所有数字之和作为得分,两人的策略都是使自己的得分尽可能高,并且都足够聪明,求A的得分减去B的得分的结果. 问题分析:1.设dp[i][j]表示从第i到第j的数的序列中,双方都采取最优策略的前提下,先手得分的最大值 2.若求dp[i][j],我们可以枚举从左边

UVA 10891 Game of Sum(区间DP(记忆化搜索))

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1832 题目大意: 两个人在玩一个游戏: 给你一行n个数字,每次只能从左端或者右端取一个或多个数字. 每个人的分值就是他们各自取得的数字之和. 假设两人都足够聪明,问先手最多能比后手多多少分. 解题思路: 其实题目意思就是先手最多能得到多少分. 设dp[l][r]是取完[l,r]的

UVA - 10891 —— Game of Sum

题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19461 这道题是一道很好的线性DP的题目,这种双头都可以选取的,可以运用带有头.尾位置信息的状态 dp[i][j] := 以第i位开头,第j位结尾的子问题的最优解 dp[i][j] = max(sum(i, i+k1) - dp[i+k1+1][j], sum(i, j-k2) - dp[i][j-k2-1])  (当 i <= j,注:i+k1 <= j &

【UVA】108 - Maximum Sum(DP矩阵)

n^3的复杂度计算最小子矩阵,用了最大连续和的DP算法. 14273282 108 Maximum Sum Accepted C++ 0.013 2014-09-27  #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int INF = 1 << 30; const int maxn = 127 + 3; int mat[maxn][maxn]