Codeforces 1311D

题目大意:

给定三个整数 a b c

给三个数字任意一个 +1 或 -1 算一次操作

求最少的操作次数,使得 b%a==0 且 c%b==0

输出最少操作次数及操作后的 a b c

a,b,c<=10000  T<=100

解题思路:

首先想到找规律,可以分成12种情况,a不变bc变共4种,b不变ac变共4种,c不变ab变共4种

但是这里是基于一个假设,即三个数中至少有一个数固定不改变,作为求其他两个答案的基准

但事实上,这种假设不可行,反例有 11 21 41,最少执行三次,即每个数 -1 即可,但这种方案三个数都进行了改变

所以找规律这个基础的办法不可行

于是就想到了枚举,枚举所有满足题意的 a b c ,再通过与给定的 a b c 绝对值差之和取小来找答案

需要注意的是,虽然 a b c<=10000,但是可能移动后的答案会超出10000这个界限(当 abc 内存在一个质数时)

例如:1 137 10000

因为10001是137的倍数,所以答案为1 137 10001

此时c超出了10000的界限

例如:137 10000 10000

可得答案为137 10001 10001

此时b与c都超出了界限

(因为a总是小于等于b,a如果为一个大质数,要使b%a==0成立,改变a时又总满足a<=b,所以a保证在10000内)

值域质数对答案会造成多大的影响

这需要举很多质数例子去验证

保险起见我用了11000作为最终的bc枚举界限(保证别TLE啥都好)

这样的复杂度小于6e5

乘以最大T,最坏情况复杂度为O(6e7),满足题意

(93ms/2000ms)

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
void solve(){
    int a,b,c,i,j,k,ans[4]={INF,0,0,0},d;
    cin>>a>>b>>c;
    if(b%a==0&&c%b==0){
        cout<<"0
"<<a<<' '<<b<<' '<<c<<'
';
        return;
    }//特判
    for(i=1;i<=10000;i++)
        for(j=i;j<=11000;j+=i)
            for(k=j;k<=11000;k+=j){
                d=abs(a-i)+abs(b-j)+abs(c-k);
                if(d<ans[0]){
                    ans[0]=d;
                    ans[1]=i;
                    ans[2]=j;
                    ans[3]=k;
                }
            }
    cout<<ans[0]<<'
'<<ans[1]<<' '<<ans[2]<<' '<<ans[3]<<'
';
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;cin>>T;while(T--)
        solve();
    
    return 0;
}
原文地址:https://www.cnblogs.com/stelayuri/p/12463303.html