codeforces 251C C. Number Transformation(数论+dp)

题目链接:

codeforces 251C


题目大意:

给出两个数a,b,k有两种操作,a-=1,或者a-=a%x(2<=x<=k),问最少需要多少步操作能够使a变成b


题目分析:

  • 首先我们考虑数据范围小的怎么做, dp[i]ai
  • {dp[i1]=min(dp[i1],dp[i]+1)dp[ii%x]=min{(dp[ii%x],dp[i]+1)|2xk}
  • 那么我们考虑题目给出的数据范围好大,直接做肯定超时,那么考虑每步操作只有a-=1和a-=a%x,那么我们考虑每次决策如果不选1的话,那么可能会更快的到达,但是如果所有的x都会被整除,那么选择1反而会得到最优解,所有的x都被整除,那么此时的数一定是所有x的lcm的倍数。
    {a=plcm+ba=p1x1+b1a=plcm+p3x1+b1ab1=plcm+p3x1ab1=plcm+q ( q=p3x1)ab1=plcm+p4x2+b2ab1b2=plcm+p4x2ai=1nbi=plcm+pnxn

    所以每个lcm都是可达的,且一定要到达的,因为通过如上操作是不能跳过某一个lcm的倍数的,所以我们利用lcm分块,然后只需要根据性质,对相同性质的块操作只做一次就可以了。

AC代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define MAX 400007

using namespace std;

typedef long long LL;
LL a,b,dp[MAX];
int k;

LL gcd ( LL a , LL b )
{
    return b==0?a:gcd(b,a%b);
}

LL solve ( LL a , LL b )
{
    memset ( dp, 0x3f , sizeof ( dp ) );
    dp[a] = 0;
    for ( int i = a ; i > b ; i-- )
    {
        dp[i-1] = min( dp[i]+1 , dp[i-1] );
        for ( int j = 2 ; j <= k ; j++ )
            dp[i-i%j] = min ( dp[i-i%j] , dp[i]+1 );
    }
    return dp[b];
}

int main ( )
{
    while ( ~scanf ( "%lld%lld%d" , &a , &b , &k ) )
    {
        LL lcm = 2;
        for ( int i = 3; i <= k ; i++ )
        {
            int d = gcd ( i , lcm );
            lcm *= i;
            lcm /= d;
        }
        LL ans;
        if ( a/lcm == b/lcm )
            ans = solve ( a%lcm , b%lcm );
        else 
            ans = solve ( a%lcm , 0 ) + (a/lcm-b/lcm-1)*solve ( lcm , 0 ) + solve ( lcm , b%lcm );
        printf ( "%lld\n" , ans );
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值