本题可以通过求解模线性方程来解决。题目的最终任务是将所有杯子翻转,所以每个杯子被翻转次数一定是奇数次。我们不妨设第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; }