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];
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值