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

题目链接:

codeforces 251C


题目大意:

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


题目分析:

  • 首先我们考虑数据范围小的怎么做,定义状态dp[i]表示从a到达i最少需要多少步
  • {dp[i?1]=min(dp[i?1],dp[i]+1)dp[i?i%x]=min{(dp[i?i%x],dp[i]+1)|2≤x≤k}
  • 那么我们考虑题目给出的数据范围好大,直接做肯定超时,那么考虑每步操作只有a-=1和a-=a%x,那么我们考虑每次决策如果不选1的话,那么可能会更快的到达,但是如果所有的x都会被整除,那么选择1反而会得到最优解,所有的x都被整除,那么此时的数一定是所有x的lcm的倍数。

    {a=p?lcm+ba=p1?x1+b1?a=p?lcm+p3?x1+b1?a?b1=p?lcm+p3?x1?a?b1=p?lcm+q ( q=p3?x1)?a?b1=p?lcm+p4?x2+b2?a?b1?b2=p?lcm+p4?x2同理可得,?a?∑i=1nbi=p?lcm+pn?xn

    所以每个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 );
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 10:40:22

codeforces 251C C. Number Transformation(数论+dp)的相关文章

BZOJ 3858 Number Transformation 数论

题目大意:给定n,k,i从1到k循环一遍,每次将n更新成i的倍数中第一个大于等于n的 求最终的n 逗比题... 我们会发现当i>=sqrt(n)时,ceil(n/i)每次都是一样的- - ↑不能理解这句话的注意n是变化的 于是当i>=sqrt(n)时只需要输出ceil(n/i)*k即可 别的做法基本都卡了- - #include <cstdio> #include <cstring> #include <iostream> #include <algo

Codeforces 251C Number Transformation

Number Transformation 我们能发现这个东西是以2 - k的lcm作为一个循环节, 然后bfs就好啦. #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int,

Codeforces 346C Number Transformation II 构造

题目链接:点击打开链接 = = 990+ms卡过 #include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<vector> #include<set> using namespace std; #define N 100010 #define L(x) (x<<1) #define R(x) (x<<

数论 Number Transformation HDU4952

已知n,k,操作k次,每次操作求大于n且能被次数i整除的最小的数 已知x*i,所以(i+1)*y>=x*i,y>=x-[x/(i+1)],当x<i+1时,y的值不再改变,直接break,输出y*k即可(x,y都是倍数) #include <stdio.h> int main() { long long n,k; long long i; int time=0; while(scanf("%I64d%I64d",&n,&k)!=-1) { i

CodeForces 346C Number Transformation II

Number Transformation II 题解: 对于操作2来说, a - a % x[i] 就会到左边离a最近的x[i]的倍数. 也就是说 [ k * x[i] + 1,  (k+1)* x[i] -1 ]这段区间的的数都会走到 k * x[i]上. 所以对于每个位置都先计算出他到右边最远的覆盖位置. 然后在反着求出每个位置能往左走走到的最远的位置. 代码: #include<bits/stdc++.h> using namespace std; #define Fopen freo

Codeforces 55D Beautiful Number

Codeforces 55D Beautiful Number a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits. Input The first line of the input contains the number of cases t (1 ≤ t ≤ 10). Each of the next t lines contains two

codeforces 148E Aragorn&#39;s Story 背包DP

Aragorn's Story Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/148/E Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who

Codeforces Round #261 (Div. 2) E (DP)

E. Pashmak and Graph Pashmak's homework is a problem about graphs. Although he always tries to do his homework completely, he can't solve this problem. As you know, he's really weak at graph theory; so try to help him in solving the problem. You are

Codeforces 837E Vasya&#39;s Function - 数论

Vasya is studying number theory. He has denoted a function f(a, b) such that: f(a, 0) = 0; f(a, b) = 1 + f(a, b - gcd(a, b)), where gcd(a, b) is the greatest common divisor of a and b. Vasya has two numbers x and y, and he wants to calculate f(x, y).