zoukankan      html  css  js  c++  java
  • [ABC193E] Oversleeping

    前言

    扩展欧几里得?几万年前学的东西,幸好最后写出来了,但还是值得复习一下(指水题解)

    题目

    AtCoder

    题目大意:

    (T) 组数据。

    时间从 (0) 时刻开始,有一辆火车从 (A) 地出发,在 (A) 地与 (B) 地之间来回跑,单趟时间为 (X) 秒,每到一个地点停 (Y) 秒。

    你初始在 (B) 地,先睡 (P) 秒,再醒着 (Q) 秒,一直循环。

    询问你是否可以上车,即是否存在一个时刻你醒着,且车停在 (B) 地。如果可以,输出最小的上车时间。如果不能,输出 infinity

    (1le Tle 10;1le X,Ple 10^9;1le Y,Qle 500.)

    讲解

    你看这个 (Y,Q) 这么小,一看就可以枚举,记为 (y,q)

    那么这就可以转换为一个同余方程问题,我们设火车经历 (i) 个周期,人经历 (j) 个周期,可列出方程:

    [X+i(2X+2Y)+y = Pj+Q(j-1)+q ]

    变形可得:

    [j(P+Q)-i(2X+2Y) = Q+X+y-q ]

    (a=P+Q,b=(2X+2Y),d=gcd(a,b)),于是用扩展欧几里得先求出特殊解,然后再找最小的时间即可。

    值得注意的是,(i,jge 0),但此时我们需要解的方程其实是:(aj-bi=kd),但扩欧解的方程是 (aj+bi=d),所以我们解出来的 (i) 需要满足小于等于 (0)

    找最小的时间其实就是找最大的 (iin(-infty,0]) 且最小的 (jin[0,+infty)),再根据他们算就行。

    实现其实不难。

    代码

    LL exgcd(LL a,LL b,LL &x,LL &y)
    {
    	if(!b)
    	{
    		x = 1;
    		y = 0;
    		return a;
    	}
    	LL ret = exgcd(b,a%b,y,x);
    	y -= x*(a/b);
    	return ret;
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	for(int T_T = Read(); T_T ;-- T_T)
    	{
    		X = Read(); Y = Read(); //on the way,stopping
    		P = Read(); Q = Read(); //asleep,awake
    		LL ans = INF,J,I;
    		LL d = exgcd(P+Q,2*(X+Y),J,I);
    		for(int y = 0;y < Y;++ y) 
    			for(int q = 0;q < Q;++ q)
    			{
    				LL deng = Q+X+y-q,i,j;
    				if(deng % d) continue;
    				j = J; i = I;
    				LL t1 = (P+Q) / d,t2 = 2*(X+Y) / d; i *= (deng / d); j *= (deng / d);
    				if(i > 0) 
    				{
    					LL woc = i / t1;
    					i -= woc * t1;
    					j += woc * t2; 
    				}
    				if(j < 0)
    				{
    					LL woc = (-j) / t2;
    					j += woc * t2;
    					i -= woc * t1;
    				}
    				while(i > 0 || j < 0) i = i - t1,j = j + t2;
    				LL wrng = Min((-i) / t1,j / t2);//both too large
    				i += wrng * t1;
    				ans = Min(ans,X+y+2*(-i)*(X+Y));
    			}
    		if(ans == INF) printf("infinity
    ");
    		else Put(ans,'
    ');
    	}
    	return 0;
    }
    /*
    草稿纸
    X+2iX+2iY+y = Pj+Q(j-1)+q
    X+2iX+2iY+y = Pj+Qj-Q+q
    2i(X+Y)-j(P+Q) = q-Q-X-y
    j(P+Q)-i(2X+2Y) = Q+X+y-q
    
    a(x+b)+b(y-a) = d
    k(a(x+b)+b(y-a)) = kd
    */
    
  • 相关阅读:
    将C#文档注释生成.chm帮助文档
    Gacutil.exe(全局程序集缓存工具)
    虚拟分区安装
    ListView控件绑定DataSet
    DataSet之增删改查操作(DataGridView绑定)
    Win8系统如何关闭用户账户控制UAC
    win8系统 重装系统如何删除EFI分区
    win8系统 如何默认显示文件扩展名和显示隐藏文件
    win8系统 如何不显示这台电脑的文件夹
    Win7 本地打印后台处理程序服务没有运 怎么办
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/14806488.html
Copyright © 2011-2022 走看看