zoukankan      html  css  js  c++  java
  • 题解 UVA11361 【Investigating DivSum Property】

    dfs实现数位DP

    int dfs(int d,int m1,int m2,bool fl)

    d:正在填从右往左第d位

    m1表示数字和%k余数,m2表示该数%k余数

    fl=1表示达到当前上限,0表示没限制(数位DP常规操作)……

    我一开始是从最高位开始枚举的,但是出了些问题,现在这个写法是从最低位枚举。

    之后自然就有dfs(d,m1,m2,fl)+=dfs(d-1,(m1+i)%k,(m2*10+i)%k,(i==num)&&fl)

    部分详解参见代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    int t,a,b,k,dp[35][110][110],c[35];//数组为什么那么小待会儿解释
    int dfs(int d,int m1,int m2,bool fl){
        //正在填从右往左第d位,
        //m1表示数字和%k余数,m2表示该数%k余数
        //fl=1表示有限制,否则是没限制 
        //每次在尾巴上多加一位 
        if(d==0) return m1==0&&m2==0;//填完了 
        if(dp[d][m1][m2]!=-1&&!fl) return dp[d][m1][m2];//填过了,直接写答案 
        int num=9,ret=0;
        if(fl) num=c[d];//确认枚举的num,没限制就是9,有限制就是0 
        for(int i=0;i<=num;i++)
            ret+=dfs(d-1,(m1+i)%k,(m2*10+i)%k,(i==num)&&fl);
        //转移
        //没限制时:无论怎么填都是没限制
        //有限制:<num可以没限制了,=num还有限制
        //i==num&&fl 
    	if(!fl) dp[d][m1][m2]=ret;
        return ret;
    }
    int solve(int x){
        memset(dp,-1,sizeof(dp));//清零
        int len=0;
        while(x){
        	c[++len]=x%10;
        	x/=10;
    	}//分割数
        return dfs(len,0,0,1);
    }
    int main(){
        scanf("%d",&t);
        while(t--){
            scanf("%d%d%d",&a,&b,&k);
            if(k>=100) printf("0\n");
            //最多10位,数字和99,大于等于100的k肯定没有答案,解决了数组的问题
            else printf("%d\n",solve(b)-solve(a-1));
        }
        return 0;
    }
    

    重要提醒:

    白书P114公式疑有错,而且和我的转移方法略有不同,但不论怎么说这个dp的设计还是非常妙的。

    数据范围似乎是假的,如果你数组开的是dp[15][105][105]wa了,请改成dp[35][110][110]即可AC,把我给坑了

    代码结构基本上是对的,但是极有可能发生和题解写的一模一样而WA或TLE的情况,这似乎是这题本身的问题,它的数据范围真的有毒。其中有一份代码洛谷TLE,在vjudgeWA,严重惊恐

    应该没有什么其他问题了。Hzao的题解和书上有些地方相似,如果有问题可以看看那篇,ta纠正了书上公式的错误。

    ——ACwisher

    qaqaq
  • 相关阅读:
    【转】VC 隐藏模块、MFC 改变窗口类名
    【转】Reason: The specified virtual disk needs repair.
    关于CreateProcess函数一些经验
    利用NtQuerySystemInformation函数遍历进程,遍历线程,获取线程挂起或运行状态
    uefi安装win7,deepin15双系统后grub没有windows选项
    X64下的虚拟地址到物理地址的转换
    WinDBG 技巧:列出模块(DLL/EXE)里面所有的符号(symbol)
    windows7内核分析之x86&x64第二章系统调用
    使用VS Code写PHP并进行调试
    使用CreateProcess创建新的process 并返回process运行结束返回值
  • 原文地址:https://www.cnblogs.com/zdsrs060330/p/13095083.html
Copyright © 2011-2022 走看看