cf201.div1 Number Transformation II 【贪心】

1 题目描述:

  被给一系列的正整数x1,x2,x3...xn和两个非负整数a和b,通过下面两步操作将a转化为b:

  1.对当前的a减1。

  2.对当前a减去a % xi (i=1,2...n)。

  计算a转化到b最小需要的最短步数。

2 输入

  第一行包含简单的整数n(1 ≤  n ≤ 10^5),第二行包含n个用空格分开的整数x1,x2,x3...xn(2 ≤  xi ≤ 10^9),第三行包含两个整数a和b(0  ≤ b ≤  a ≤ 10^9a - b ≤ 10^6)。

3 输出

  输出一个整数,a转化为b的最小步数。

4 思路

  假设dp[k]表示从k+b转化到b所需要的最小步数,然后可以通过计算next=(b+k)-(b+k) % xi(i=1,2..n, next >= b)所能达到的最小值来计算dp[k],即dp[k]=dp[next-b]+1,这其实是一个贪心的选择,总是让每一步尽量产生大的跨度。为什么可以这样计算?由于dp[k]是一个递增函数。假设存在t,使得dp[k] = dp[k - t] + 1(k+b通过一步可以转化到k-t+b),如果t=1,显然dp[k-1]<dp[k];如果t > 1, 必然有dp[k-1] <= dp[k - t]+1,因为k+b可以通过一步转化为k-t+b,那么k-1+b也必然存在一步转化为k-t+b(只要k+b先-1转化为k+b-1,然后k+b-1必然就可以转化为k-t+b)。

5实现

 1 #include <stdio.h>
 2 #include <iostream>     // std::cout
 3 #include <algorithm>    // std::sort
 4 #include <vector>       // std::vector
 5 #include <functional>
 6 
 7 #define min(a, b) ((a) < (b) ? (a) : (b))
 8 int n, x[100005], a, b;
 9 
10 int main ( int argc, char *argv[] )
11 {
12     int i, t, tt, ans;
13 
14     scanf("%d", &n);
15     for(i = 0; i < n; i++)
16         scanf("%d", &x[i]);
17     scanf("%d%d", &a, &b);
18     std::sort(x, x + n, std::greater<int>());
19     n = std::unique(x, x + n) - x;
20 
21     ans = 0;
22     while (a != b)
23     {
24         tt = a - 1;
25         for (i = 0; i < n; i++)
26         {
27             t = a - (a % x[i]);
28             if (t < b)
29                 x[i--] = x[--n];
30             else
31                 tt = min(t, tt);
32         }
33         a = tt;
34         ans++;
35     }
36     printf("%d\n", ans);
37     return 0;
38 }                /* ----------  end of function main  ---------- */
posted @ 2013-09-25 21:50  在于思考  阅读(400)  评论(0编辑  收藏  举报