POJ3373:Changing Digits(记忆化)

Description

Given two positive integers n and k, you are asked to generate a new integer, say m, by changing some (maybe none) digits of n, such that the following properties holds:

  1. m contains no leading zeros and has the same length as n (We consider zero itself a one-digit integer without leading zeros.)
  2. m is divisible by k
  3. among all numbers satisfying properties 1 and 2, m would be the one with least number of digits different from n
  4. among all numbers satisfying properties 1, 2 and 3, m would be the smallest one

Input

There are multiple test cases for the input. Each test case consists of two lines, which contains n(1≤n≤10100) and k(1≤k≤104kn) for each line. Both n and k will
not contain leading zeros.

Output

Output one line for each test case containing the desired number m.

Sample Input

2
2
619103
3219

Sample Output

2
119103

看到一篇博客解释的非常详细,在此引用一下,传送门:http://blog.csdn.net/lyy289065406/article/details/6698787/

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

char s[105];
int dp[105][10],tem[105],a[105],mod,len,f[105][10005],k;

void init()
{
    int i,j;
    for(i = 0; i<=9; i++)
        dp[1][i] = i%mod;
    for(i = 2; i<=len; i++)
        for(j = 0; j<=9; j++)
            dp[i][j] = (dp[i-1][j]*10)%mod;
    memset(f,0,sizeof(f));
}

bool dfs(int cnt,int l,int k)//从l开始,还要改变cnt个数字,使得余数k变为0
{
    int i,j;
    if(!k)
    {
        for(i = 0; i<len; i++)
            printf("%d",tem[i]);
        printf("\n");
        return 1;
    }
    if(!cnt) return 0;
    if(l>len-1) return 0;
    if(f[l][k]>=cnt) return 0;
    for(i = l; i<len; i++)//高位开始,从小取
    {
        for(j = 0; j<a[i]; j++)
        {
            if(!i && !j)
                continue;
            tem[i] = j;
            int temp = (k-dp[len-i][a[i]]+dp[len-i][j])%mod;
            if(temp<0)
                temp+=mod;
            if(dfs(cnt-1,i+1,temp))
                return 1;
        }
        tem[i] = a[i];
    }
    for(i = len-1; i>=l; i--)//低位开始,要变大
    {
        for(j = a[i]+1; j<=9; j++)
        {
            if(!i && !j)
                continue;
            tem[i] = j;
            int temp = (k-dp[len-i][a[i]]+dp[len-i][j])%mod;
            if(temp<0)
                temp+=mod;
            if(dfs(cnt-1,i+1,temp))
                return 1;
        }
        tem[i] = a[i];
    }
    f[l][k] = cnt;//l开始取cnt个数不能使得k变为0
    return 0;
}

int main()
{
    int i,j;
    while(~scanf("%s",s))
    {
        scanf("%d",&mod);
        len = strlen(s);
        init();
        k = 0;
        for(i = 0; i<len; i++)
            tem[i] = a[i] = s[i]-'0';
       for(i = len-1; i>=0; i--)
           k = (k+dp[len-i][a[i]])%mod;
        for(i = 0; i<len; i++)
            if(dfs(i,0,k))
                break;

    }

    return 0;
}

POJ3373:Changing Digits(记忆化)

时间: 2024-10-13 14:37:58

POJ3373:Changing Digits(记忆化)的相关文章

POJ 3373 Changing Digits

题目大意: 给出一个数n,求m,使得m的长度和n相等,能被k整除.有多个数符合条件输出与n在每位数字上改变次数最小的.改变次数相同的输出大小最小的.  共有两种解法:DP解法,记忆化搜索的算法. 以后会更新记忆化搜索. 1.DP解法: 解题思路: DP[i][j]表示数n的前i位除以k余j最小改变几位. DP[len][0]就表示数n被k整除最小改变几位. 根据这个关系从后向前遍历DP数组可以找出所有满足条件的数的路径. 再根据关系从前往后输出.  下面是代码: #include <stdio.

POJ 3373 Changing Digits 好蛋疼的DP

一开始写的高位往低位递推,发现这样有些时候保证不了第四条要求.于是又开始写高位往低位的记忆化搜索,又发现传参什么的蛋疼的要死.然后又发现高位开始的记忆化搜索就是从低位往高位的递推呀,遂过之. dp[i][j]记录在i位 且 余数为j时的最优解情况. dp[i][j].next表示当前的最优解是由哪一种状态转移过来的. 代码又写锉了.. #include <algorithm> #include <iostream> #include <cstring> #include

POJ 2704 Pascal&#39;s Travels (基础记忆化搜索)

Pascal's Travels Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5328   Accepted: 2396 Description An n x n game board is populated with integers, one nonnegative integer per square. The goal is to travel along any legitimate path from t

hdu 5098 Smart Software Installer 拓扑排序or记忆化搜索

Smart Software Installer Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 416    Accepted Submission(s): 124 Problem Description The software installation is becoming more and more complex. An a

hdu 5787 数位dp,记忆化搜索

题意:求区间[l,r]内有多少个数符合,这个数的任意的相邻k位数(digits),这k个数都两两不相等 l,r范围是1~1e18,k是2~5 思路:数位DP,因为K<=5,我们最多需要保存下来当前位的前4位就足够了.因为dp[pos][p1][p2][p3][p4]表示,现在枚举取第pos位,pos位之前的四位分别为p1,p2,p3,p4,p4是pos的上一位.那么p1~p4的范围就是0~9,但是因为总位数小于当前数字的位数的数也要进行枚举,需要一个数字来区分它是前导0还是在中间时为0,令p =

URAL 1501. Sense of Beauty(记忆化搜索 dfs)

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1501 The owner of a casino for New Russians has a very refined sense of beauty. For example, after a game there remain two piles with the same number of cards on the table, and the owner likes the car

HDU 1513 Palindrome:LCS(最长公共子序列)or 记忆化搜索

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1513 题意: 给你一个字符串s,你可以在s中的任意位置添加任意字符,问你将s变成一个回文串最少需要添加字符的个数. 题解1(LCS): 很神奇的做法. 先求s和s的反串的LCS,也就是原串中已经满足回文性质的字符个数. 然后要变成回文串的话,只需要为剩下的每个落单的字符,相应地插入一个和它相同的字符即可. 所以答案是:s.size()-LCS(s,rev(s)) 另外,求LCS时只会用到lcs[i-

uva 1076 - Password Suspects(AC自动机+记忆化搜索)

题目链接:uva 1076 - Password Suspects 题目大意:有一个长度为n的密码,存在m个子串,问说有多少种字符串满足,如果满足个数不大于42,按照字典序输出. 解题思路:根据子串构建AC自动机,然后记忆化搜索,dp[i][u][s]表示第i个字符,在u节点,匹配s个子串. #include <cstdio> #include <cstring> #include <queue> #include <string> #include <

HDU 1978 How many ways(记忆化)

Description 这是一个简单的生存游戏,你控制一个机器人从一个棋盘的起始点(1,1)走到棋盘的终点(n,m).游戏的规则描述如下: 1.机器人一开始在棋盘的起始点并有起始点所标有的能量. 2.机器人只能向右或者向下走,并且每走一步消耗一单位能量. 3.机器人不能在原地停留. 4.当机器人选择了一条可行路径后,当他走到这条路径的终点时,他将只有终点所标记的能量. 如上图,机器人一开始在(1,1)点,并拥有4单位能量,蓝色方块表示他所能到达的点,如果他在这次路径选择中选择的终点是(2,4)