zoukankan      html  css  js  c++  java
  • CSP-S2020 贪吃蛇

    题目描述


    题解

    70分没想清楚+时间不够=20分

    考场上的奇妙做法:

    假设每条蛇都没有脑子,不管自己的死活往下吃,那么最后会形成一棵操作树,(u,v,t)表示u在t时间吃了v

    显然根不会被吃,所以其相连的有危险,所以它们会放掉自己儿子中时间最大的那个,设其为y父亲为x,则非x外的蛇知道y是最大的,所以如果它们不放的话x必须要放,x也知道别的蛇不会放,所以它也会放了y,并且这样对所有有危险的蛇都是最优的

    然后有一部分蛇会脱离危险,所以它们可以继续往下吃,如此用前缀和优化一下随便维护即可做到O(n)

    问题是怎么O(n)求出操作树,具体见https://blog.csdn.net/EI_Captain/article/details/109552980

    换一种做法(Orz lk),如果一条蛇吃完后不会变成最小的则它一定会吃,因为下一条蛇吃了之后会比自己更小,死得比自己快,所以把锅丢给它

    如果变成最小的,那么往后找出按照这样吃第一条不会变成最小的蛇,那么它一定会吃,下一条一定不吃,下下条一定会吃,按照奇偶性讨论

    用两个队列即可维护,只要没有出现变成最小的话那么max递减min递增,相减得到的递减丢到第二个队列里

    如果变成最小的,那么每次只能跑到末尾否则就停

    时间复杂度O(n)

    code

    #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 ll long long
    #define file
    using namespace std;
    
    struct type{int s,x;} s1,s2;
    struct Queue{type d[1000001];int h,t;
    	void push(type s) {d[++t]=s;}
    	void pop(bool tp) {if (!tp) ++h; else --t;}
    	void clear() {h=1,t=0;}
    	bool empty() {return h>t;}
    	type head() {return d[h];}
    	type tail() {return d[t];}
    } q[2];
    int a[1000001],T,n,i,j,k,l,I,x,y,ans,I1,I2,sum;
    
    bool operator < (type a,type b) {return a.s<b.s || a.s==b.s && a.x<b.x;}
    bool operator > (type a,type b) {return a.s>b.s || a.s==b.s && a.x>b.x;}
    void swap(int &x,int &y) {int z=x;x=y;y=z;}
    
    int main()
    {
    //	freopen("snakes.in","r",stdin);
    //	#ifdef file
    //	freopen("snakes.out","w",stdout);
    //	freopen("b.out","w",stdout);
    //	#endif
    	
    	scanf("%d",&T);
    	fo(I,1,T)
    	{
    		if (I==1)
    		{
    			scanf("%d",&n);
    			fo(i,1,n) scanf("%d",&a[i]);
    		}
    		else
    		{
    			scanf("%d",&k);
    			fo(i,1,k) scanf("%d%d",&x,&y),a[x]=y;
    		}
    		
    		q[0].clear(),q[1].clear(),ans=n;
    		I1=0,I2=1;
    		fd(i,n,1) q[I1].push(type{a[i],i});
    		while (ans>1)
    		{
    			--ans;
    			if (q[I2].empty() || q[I1].tail()<q[I2].tail()) s2=q[I1].tail(),q[I1].pop(1); else s2=q[I2].tail(),q[I2].pop(1);
    			if (!s2.s) continue;
    			if (q[I2].empty() || q[I1].head()>q[I2].head()) s1=q[I1].head(),q[I1].pop(0); else s1=q[I2].head(),q[I2].pop(0);
    			
    			s1.s-=s2.s;
    			if (q[I1].empty()) swap(I1,I2);
    			q[I2].push(s1);
    			if (q[I1].tail()>s1) break;
    		}
    		if (ans>1)
    		{
    			sum=0;
    			while (sum<ans-1)
    			{
    				if (q[I2].empty() || q[I1].tail()<q[I2].tail()) s2=q[I1].tail(),q[I1].pop(1); else s2=q[I2].tail(),q[I2].pop(1);
    				if (q[I2].empty() || q[I1].head()>q[I2].head()) s1=q[I1].head(),q[I1].pop(0); else s1=q[I2].head(),q[I2].pop(0);
    				
    				s1.s-=s2.s;
    				if (q[I1].empty()) swap(I1,I2);
    				if (!q[I1].empty() && q[I1].tail()<s1 || !q[I2].empty() && q[I2].tail()<s1) break;
    				q[I2].push(s1);
    				++sum;
    			}
    			sum+=sum==(ans-1);
    			ans+=!(sum&1);
    		}
    		
    		printf("%d
    ",ans);
    	}
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    python 继承与组合
    google浏览器安装不上的绝望经历
    python 类,对象
    Javascript学习笔记——闭包
    面试小结:html/css实现元素居中
    @清晰掉 qsort()
    @清晰掉 sprintf sscanf双胞胎
    @清晰掉 GDB调试器中的战斗机
    @大脑练习: 计算两个矩阵的乘积
    js测试用
  • 原文地址:https://www.cnblogs.com/gmh77/p/13956086.html
Copyright © 2011-2022 走看看