• CF1276E


    题目大意

    4个相同石头在坐标轴的整点上,每次选定两个石头把一个根据另一个对称(x-->2y-x),求一种方案使得石头被移到给定位置

    判断无解或用<=1000步完成

    题解

    神仙构造题

    特判掉a全部相等的情况,设g=gcd(ai-a0),则ab中都应该根据g同余,否则显然不能跳

    设余数为d,更进一步发现(a-d)/g中的奇数/偶数个数即等于(b-d)/g中的奇数/偶数个数,因为一次跳不能改变奇偶

    然后把a和b变成(a/b-d)/g,最后还原一下

    考虑构造解,分两步进行:

    ①把a/b分别移到[x,x+1]和[y,y+1]

    ②把[x,x+1]移到[y,y+1]

    最后把b的操作反过来即可,以下均假设a单调递增

    第一部分:

    设d=(a3-a0+2)/4,考虑每次把l减少1/4

    假设a1或a2∈[a0+l,a3-l],那么显然可以把a0或a3折到中间

    否则考虑用log次操作使得a0a3不变(或a3-a0更小)并且把a1a2移到中间

    ①若a1a2分别在两侧,则选择靠两边距离较小(另一边必然大于0)的那个进行操作

    假设是a1,那么就把a1先按a2翻转,再按a3翻转,结果会变成a0+2(a3-a2)

    对两边轮流做,次数是log的(其实是斐波那契数)

    ②若a1a2在同一侧,则每次把a0/a3按照a2/a1翻转,次数也是log的

    第二部分:

    设当前a3-a0=l,那么可以通过整体翻转来移动l的长度

    定义扩展操作,即把a2按a0翻转,a1按a3翻转,这样长度至少*2

    所以扩展到一次不超过距离的最大长度即可,之后不断还原回去同时逼近[y,y+1]即可

    总次数也是log的,注意最后的l要为1

    code

    挂了10发

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define abs(x) ((x)>0?(x):-(x))
    #define ll long long
    //#define file
    using namespace std;
    
    struct Ans{
    	ll a[1001][2];
    	int tot;
    	void add(ll x,ll y) {if (x==y) return;++tot;a[tot][0]=x;a[tot][1]=y;}
    } A,B;
    ll a[4],b[4],d,g;
    int i,j,k,l;
    
    ll gcd(ll x,ll y) {ll r=x%y; while (r) x=y,y=r,r=x%y; return y;}
    ll turn(ll t) {return t*g+d;}
    
    void Turn(ll *a) {fo(i,0,3) a[i]=(a[i]-d)/g;}
    void jump(ll &x,ll &y) {x=y*2-x;}
    
    void work(ll *a,Ans &b)
    {
    	ll d;
    	while (a[3]-a[0]>1)
    	{
    		d=(a[3]-a[0]+2)/4;
    		if (a[0]+d<=a[1] && a[1]<=a[3]-d)
    		{
    			if (a[1]*2-a[0]<=a[3])
    			b.add(a[0],a[1]),jump(a[0],a[1]);
    			else
    			b.add(a[3],a[1]),jump(a[3],a[1]);
    		}
    		else
    		if (a[0]+d<=a[2] && a[2]<=a[3]-d)
    		{
    			if (a[2]*2-a[0]<=a[3])
    			b.add(a[0],a[2]),jump(a[0],a[2]);
    			else
    			b.add(a[3],a[2]),jump(a[3],a[2]);
    		}
    		else
    		{
    			while (!(a[0]+d<=a[1] && a[1]<=a[3]-d) && !(a[0]+d<=a[2] && a[2]<=a[3]-d))
    			{
    				if (a[1]<a[0]+d && a[3]-d<a[2])
    				{
    					if (a[1]-a[0]<a[3]-a[2])
    					b.add(a[1],a[2]),jump(a[1],a[2]),b.add(a[1],a[3]),jump(a[1],a[3]);
    					else
    					b.add(a[2],a[1]),jump(a[2],a[1]),b.add(a[2],a[0]),jump(a[2],a[0]);
    				}
    				else
    				if (a[3]-d<a[1])
    				b.add(a[3],a[1]),jump(a[3],a[1]);
    				else
    				b.add(a[0],a[2]),jump(a[0],a[2]);
    				sort(a,a+4);
    			}
    		}
    		sort(a,a+4);
    	}
    }
    
    void kuo()
    {
    	A.add(a[2],a[0]),jump(a[2],a[0]);
    	A.add(a[1],a[3]),jump(a[1],a[3]);
    	sort(a,a+4);
    }
    void suo()
    {
    	A.add(a[0],a[1]),jump(a[0],a[1]);
    	A.add(a[3],a[2]),jump(a[3],a[2]);
    	sort(a,a+4);
    }
    void Work()
    {
    	ll d,l;
    	if (a[3]<=b[0])
    	{
    		while (!(a[3]-a[0]==1 && a[0]==b[0]))
    		{
    			d=b[3]-a[3],l=a[3]-a[0];
    			if (l>=d)
    			{
    				while (l>max(d,b[3]-b[0])) suo(),d=b[3]-a[3],l=a[3]-a[0];
    				if (a[0]!=b[0] || a[3]!=b[3])
    				fo(i,0,2) A.add(a[i],a[3]),jump(a[i],a[3]);
    			}
    			else
    			{while (l<d) kuo(),d=b[3]-a[3],l=a[3]-a[0];}
    			sort(a,a+4);
    		}
    	}
    	else
    	if (b[3]<=a[0])
    	{
    		while (!(a[3]-a[0]==1 && a[0]==b[0]))
    		{
    			d=a[0]-b[0],l=a[3]-a[0];
    			if (l>=d)
    			{
    				while (l>max(d,b[3]-b[0])) suo(),d=a[0]-b[0],l=a[3]-a[0];
    				if (a[0]!=b[0] || a[3]!=b[3])
    				fd(i,3,1) A.add(a[i],a[0]),jump(a[i],a[0]);
    			}
    			else
    			{while (l<d) kuo(),d=a[0]-b[0],l=a[3]-a[0];}
    			sort(a,a+4);
    		}
    	}
    }
    
    int main()
    {
    	#ifdef file
    	freopen("CF1276E.in","r",stdin);
    	#endif
    	
    	fo(i,0,3) scanf("%lld",&a[i]);sort(a,a+4);
    	fo(i,0,3) scanf("%lld",&b[i]);sort(b,b+4);
    	if (a[3]==a[0] || b[3]==b[0])
    	{
    		if (a[3]==a[0] && b[3]==b[0] && b[0]==a[0]) printf("0
    "); else printf("-1
    ");
    		return 0;
    	}
    	
    	g=a[3]-a[0];
    	fo(i,1,2) if (a[i]>a[0]) g=gcd(g,a[i]-a[0]);
    	d=((a[0]%g)+g)%g;
    	
    	Turn(a);
    	l=b[3]-b[0];
    	fo(i,1,2) if (b[i]>b[0]) l=gcd(l,b[i]-b[0]); if (l!=g) {printf("-1
    ");return 0;}
    	fo(i,0,3)
    	if ((b[i]%g+g)%g!=d) {printf("-1
    ");return 0;}
    	Turn(b);
    	k=l=0;
    	fo(i,0,3) if (a[i]&1) ++k; else ++l;
    	fo(i,0,3) if (b[i]&1) --k; else --l;
    	if (k && l) {printf("-1
    ");return 0;}
    	
    	work(a,A),work(b,B);
    	Work();
    	
    	printf("%d
    ",A.tot+B.tot);
    	fo(i,1,A.tot) printf("%I64d %I64d
    ",turn(A.a[i][0]),turn(A.a[i][1]));
    	fd(i,B.tot,1) printf("%I64d %I64d
    ",turn(B.a[i][1]*2-B.a[i][0]),turn(B.a[i][1]));
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    函数的有用信息,装饰器 day12
    函数名、闭包、装饰器 day11
    函数的动态参数与命名空间 day10
    函数 day9
    集合 day8
    文件操作 day8
    基础数据类型补充,及capy daty7
    day7 回顾
    编码补充 daty 6
    字典的增删改查 daty 5
  • 原文地址:https://www.cnblogs.com/gmh77/p/13340830.html
Copyright © 2020-2023  润新知