【Codeforces Round #614(div2)】D-Aroma's Search (贪心)

一、题目链接

https://codeforces.com/contest/1293/problem/D

二、题意

第一行给出一个点的坐标 x 0 x_0 y 0 y_0 ,以及 a x a_x a y a_y b x b_x b y b_y

当 i > 0 时,第i个点的坐标:

x i x_i = a x a_x * x i 1 x_{i-1} + b x b_x

y i y_i = a y a_y * y i 1 y_{i-1} + b y b_y

给出起始点 x s x_s y s y_s ,开始移动。每一步可以横向或纵向移动一个单位长度,记为1步。问限定t步内,至多可以采集多少点。

三、数据范围

1 ≤ x 0 x_0 , y 0 y_0 1 0 16 10^{16}

2 ≤ a x a_x , a y a_y ≤ 100

0 ≤ b x b_x , b y b_y 1 0 16 10^{16}

1 ≤ x s x_s , y s y_s , t ≤ 1 0 16 10^{16}

四、解题思路

先看数据范围,哎鸭,怎么这么大,不会了不会了。

再看一眼,发现2 ≤ a x a_x , a y a_y ≤ 100 在一堆long long型中格外醒目。尤其是下界“2"——这意味着每个点的横纵坐标 x i x_i y i y_i 至少是 x i 1 x_{i-1} y i 1 y_{i-1} 的两倍!由指数增长趋势,后面的点会离得越来越远的!

那么, 1 0 16 10^{16} 就显得格外渺小啦。 2 60 2^{60} 都有 1 0 18 10^{18} 了,平面上最多就几十个点,我才不怕呢~

又由于指数增长的特点,第i个点和第0个点的曼哈顿距离(横轴差与纵轴差绝对值的和)总小于第i个点到第i+1个点(分解到x、y轴,用指数模型理解即可)。

所以,从任意点出发,先尽可能收集左边点,有剩余步数再收集右边点,一定是最优的解法。 大!胆!贪!心!

//区间dp也可做,在这里就略了

五、AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
 
ll x[100], y[100], ax, ay, bx, by, xs, ys, t;
int ans;
 
int main()
{
    cin >> x[0] >> y[0] >> ax >> ay >> bx >> by >> xs >> ys >> t;
    int num = 0;
    while(1) //把点记录好
    {
        num++;
        x[num] = x[num - 1] * ax + bx;
        y[num] = y[num - 1] * ay + by;
        if (x[num] > xs && y[num] > ys && x[num] - xs + y[num] - ys > t) break;
        //压根走不到的点就不用记录啦
    }
    for (int i = 0; i <= num; i++) //枚举以i为起点开始收集的情况,取最大解为ans
    {
        ll sum = abs(xs - x[i]) + abs(ys - y[i]);
        //sum记录步数,初始为从起点到i点的步数
        if (sum > t) continue; 
        int now = 1; //now是以i为起点能收集的点数,现在已经收集了i点,now++
        int l = i; //向左找
        while(l > 0 && sum + x[i] - x[l - 1] + y[i] - y[l - 1] <= t) l--;
        //能走到的最小点
        sum += (x[i] - x[l] + y[i] - y[l]) * 2; 
        //由于曼哈顿距离特点,逐点计算步数与直接从i走到最小点的步数相等,所以直接找最小点计算
        //*2是算上从最小点返回的步数
        now += i - l; //更新在左边收集的点数
        int r = i; //向右找
        while(x[r + 1] > 0 && sum + x[r + 1] - x[i] + y[r + 1] - y[i] <= t) r++;
        now += r - i;
        //因为在循环里就限定了sum不会越界,所以不需要再判断sum,now一定是可行的方案
        ans = max(ans, now);
    }
    cout << ans;
    return 0;
}
发布了5 篇原创文章 · 获赞 8 · 访问量 705

猜你喜欢

转载自blog.csdn.net/weixin_45785492/article/details/104102571
今日推荐