cf-div.2-861

发布时间 2023-03-31 09:35:43作者: 安潇末痕

题目链接:https://codeforces.com/contest/1808/problem/C

又是被打爆的一场比赛。。。(本题想了一个多小时也没有想到最核心的地方。)

大致题意:让你从\([l,r]\)选择一个数字,使得它其中的数位的最大值减最小值最小。

\(l,r\)的范围都取到long long级别。

思路:单纯暴力枚举一定不行。注意到一个性质,一个数字里的数位相同的数字越多,他一定不会变得更差
所以,答案一定包含这样一种情况,前n位与l或r的前n位相同,后面全部取一样的数字,这样情况就少了很多,但最优解的子集一定包含在我们所枚举的范围里。

代码:

#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
using LL = long long;

int main(){

    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);

    auto get = [&](LL x){
        int mn = 10, mx = -1;
        while(x){
            mn = min(1LL * mn, x % 10);
            mx = max(1LL * mx, x % 10);
            x /= 10;
        }
        return mx - mn;
    };

    int T;
    cin >> T;
    while(T--){
        LL l, r;
        cin >> l >> r;

        int a[20], b[20];
        int len1 = 0, len2 = 0;

        LL num = l;
        while(num) a[++len1] = num % 10, num /= 10;
        num = r;
        while(num) b[++len2] = num % 10, num /= 10;

        int ans = 10;
        LL val = -1; 

		LL x = 0;

		for (int i=len1;i>=0;i--){
			for (int j=0;j<=9;j++){
				LL t = x;
				for (int k=i;k>=1;k--){
					t = t*10+j;
				}
				if (t>r||t<l) continue;
				if (get(t)<ans) ans = get(t),val = t;
			}
			x = x*10+a[i];
		}
		x = 0;
		for (int i=len2;i>=0;i--){
			for (int j=0;j<=9;j++){
				LL t = x;
				for (int k=i;k>=1;k--){
					t = t*10+j;
				}
				if (t>r||t<l) continue;
				if (get(t)<ans) ans = get(t),val = t;
			}
			x = x*10+b[i];
		}
		cout<<val<<'\n';
	}
}