VJ链接
题意:
对三个数a,b,c,进行若干次操作,每次操作只能对其中一个数进行+1或-1。同一个数可进行多次操作。问使得b能整除a且c能整除b的最少操作次数。(1≤a≤b≤c≤10000)
思路:
由于数据范围较小,且a和c都可以用b求得,可以暴力枚举b的所有情况,然后记录每种情况需要进行操作的次数。保留最小的一组即可。就是假设b已知的情况下去推a和c。
具体做法:
1.a用b来表示以及对a操作的次数实现:
b既定时,由于a%b==0,则a必然是b的因数,枚举b的所有因数,其中与a差值最小的那个因数即为最终的a,它们的差值就是需要对题中输入的a的操作次数。
注意枚举b的因数时,范围取1~sqrt(b),每次计算两个数
2.c用b表示以及对c的操作次数实现:
c=k*b(k=1,2,3,4…), 求与c最接近的b的整数倍即可,略
3 关于b的枚举范围:1~c+r ,r是个大概值,用于容错,实测200即可
但是r一定要有,为什么?我也不知道我为什么wa了六次,有明白的大佬希望能艾特我,不胜感激。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int t,q,w,e;
int ab(int x) //绝对值
{
return x=x>0?x:-1*x;
}
int sea(int x,int sp) //寻找与sp最接近的,x的因数值
{
int mn=inf,s,j,r;
for(int i=1; i<=sqrt(x); i++)
if(x%i==0)
{
j=x/i; //i,j,一次算俩
r=ab(i-sp);
if(mn>r)
{
mn=r;
s=i;
}
r=ab(j-sp);
if(mn>r)
{
mn=r;
s=j;
}
}
return s;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&q,&w,&e);
int X,Y,Z,minn=inf,y,y1; //X,Y,Z最终保留的abc值,minn:最少操作次数
for(int k=1; k<=e+100; k++) //b的范围,一定要扩充一下
{
int ans=0,a=q,b=w,c=e;//ans:每次的操做次数和
ans+=ab(b-k);//b需要的操作数
b=k;
if(c%k!=0)//省时间
{
y=c/k*k;
ans+=min(c-y,y+k-c);
c=(c-y)>(y+k-c)?y+k:y;//b求c
}
if(b%a!=0)
{
y1=sea(k,a);//b求a
ans+=ab(y1-a);
a=y1;
}
if(minn>ans&&c>=b&&b>=a)//因为b从1开始,但b<a没有意义
{
minn=ans;
X=a,Y=b,Z=c;
}
}
printf("%d\n%d %d %d\n",minn,X,Y,Z);
}
return 0;
}