本题可以通过求解模线性方程来解决。题目的最终任务是将所有杯子翻转,所以每个杯子被翻转次数一定是奇数次。我们不妨设第i个杯子被翻转次数为 2*ki+1,翻转总次数为n,则依题意可以列出如下方程
Sum(2*ki+1) = B*n,整理可得 2*Sum(ki) + A = B*n
我们不妨设Sum(ki)= K, 则上式可化为 2*K + A = B*n;
也就是求一个最小的n,使得 B*n – 2*K = A
对应莫线性方程为 B*n = A mod 2。
但是解出上方程最小的 n 并不能作为结果,因为题目本身存在对于K的限制,首先因为 K = Sum(ki),且 ki >= 0,所以K>=0,同时作为翻杯子的合法解,必须有所有的 2*ki + 1 <= n。也就是对于最大的ki有 2*ki<=n 成立,由于每次翻杯子与杯子的次序没有关系,所以我们可以贪心的认为让ki尽可能接近为最优,这样对于K的约束可以化为使得 2*((K+a-1)/a)+1<=n(贪心后ki最大为K/a向上取整,这里不能整理,整理之后会出错,只要还是取整除法的问题)成立,于是我们在求出一组原方程的特解之后,可以枚举或二分通解,找出满足约束的最小解即为答案。
#include <stdio.h>
#include <iostream>
using namespace std;
int x,y;
long long euclid(long long a,int b)//b*n=a%2
{
if(!b)
{
x=1,y=0;
return a;
}
int d=euclid(b,a%b);
int yy=y;
y=x-a/b*y;x=yy;
return d;
}
int main ()
{
long long a,b;
int n;
while (scanf("%I64d%I64d",&a,&b)!=EOF )
{
if((a&1) && !(b&1)){printf("No Solution!\n"); continue ;}
if(a==b){printf("1\n");continue;}
long long d=euclid(b,2);
n=x*a/d%2;
//printf("%lld %lld %lld %lld\n",n,x,y,d);
for ( ; (2*(((b*n-a)/2+a-1)/a)+1)>n || b*n-a<0; n+=2/d);
//printf("%lld %lld\n",2*(((b*n-a)/2+a-1)/a)+1,n);
printf("%d\n",n);
//cout<<n<<endl;
}
return 0;
}
找规律的方法
r | b | q | 最优解的运动次数 |
0 |
|
| q |
非0偶数 | 奇数 |
| q+2 |
偶数 | q = 1 | 3 | |
q>= 2 | q+1 | ||
奇数 | 奇数 | q = 1 | 2 |
q>=2 | q+1 | ||
偶数 |
| 无解 |
#include <stdio.h>
int main ()
{
//freopen ("cups.in","r",stdin);
unsigned long long a,b,r,q;
while (scanf("%I64d%I64d",&a,&b)!=EOF )
{
if((a&1) && !(b&1)){printf("No Solution!\n"); continue ;}
r=a%b;q=a/b;
if(!r){printf("%lld\n",q);continue;}
if(r&1) {
if(q==1)printf("%lld\n",2*((b+3*r-1)/(2*r)));
else printf("%lld\n",q+1);
}
else {
if(b&1)printf("%I64d\n",q+2);
else if(q==1)printf("3\n");
else printf("%lld\n",q+1);
}
}
return 0;
}