poj 3373 数论常识(数位dp)

本文提供了一种解决POJ 3373问题的有效方法,通过动态规划实现记忆化搜索,找到满足特定条件的整数m。m与给定的n位数相同且能被k整除,同时保证m与n不同位数最少,且m值最小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:http://poj.org/problem?id=3373
题意:

给出2个整数n(n<10^100)和k(k<10000),求满足以下条件的整数m
1、m与n位数相同
2、m能被k整除
3、满足以上两点时,m和n在相同位置的地方,数字不同的个数最少
4、满足以上三点时,m值最小

分析:

这题很容易想到怎么做:
dp[i][j][num]表示前i位数构成的数是j,改变了num次,记忆化搜索就好。
但是num最大是多少呢?
假设k的位数是m,那么n最多只要改变m为位就可以%k==0了!因为n的m位之前的数%k可以得到一个数X,后m位变成k-X就行了!
所以k最大为10000,最多改变5位就行!

代码:

const int N = 1e4 + 9;
int d[110][N][6], n, k,minn;
char s[110],ans[110];
void dfs(int pos,int pre,int num) {
    if(pos==n) {
        if(num<minn&&pre==0) {
            minn=num;
            strcpy(ans,s);
        }
        return;
    } else if(num<minn) {
        if(!d[pos][pre][num]) {
            d[pos][pre][num]=1;
            char t=s[pos];
            for(int i=0; i<=9; i++) {
                if(pos==0&&i==0)continue;
                s[pos]=i+'0';
                dfs(pos+1,(pre*10+i)%k,num+(i!=t-'0'));

            }
            s[pos]=t;
        }
    }
}
int main() {
    //freopen ("f.txt", "r", stdin);
    while (~scanf ("%s %d", s, &k) ) {
        n = strlen (s);
        memset(d,0,sizeof(d));
        minn=6;
        dfs (0, 0, 0);
        printf("%s\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值