• CSP-S2020 贪吃蛇


    参考博客:

    https://www.luogu.com.cn/blog/EntropyIncreaser/ying-ye-ri-zhi-2020117-yi-ci-xin-xi-fou-dui-cheng-yin-fa-di-csp2020-t4-post

    https://qaq-am.com/CSPS-2020-贪吃蛇/


    (n)条蛇,执行若干次这样的操作:最强的蛇(以能力值为第一关键字,编号为第二关键字)有选择是否执行的权力,如果不执行就结束,如果执行就把最弱的蛇吃掉,并且自己的能力值变成两者之间的差。

    假设所有的蛇都绝顶聪明,它们希望吃尽量多的蛇而且自己不被吃,问最终剩下多少蛇。

    (Tle 10,nle 10^6)

    保证一开始给出的序列单调递增。


    先讲一个读完题意就会的(70)分做法:由于每条蛇可以预知未来,所以它可以推演它选择吃之后的情况,推演出来如果它会死,那么就选择不吃以改变这种情况,否则选择吃。然后就直接模拟:先假设所有的蛇失去了理智,一直互相吃到最后,然后把这个情况倒推回来。到某一条蛇选择的时候,如果后面它死了,就改变未来,即将当前情况到它做出选择的这个区间的操作都撤销掉。

    于是这样最终的问题是:维护一个序列,每次取出最大值和最小值,作差后再丢进去。这个东西用set可以随便做到(O(nlg n))

    优化这个维护的过程到(O(n)),目前我只知道有EI的做法是对的(当然我没有看懂)。

    现在讲讲LK的做法:

    考虑如果一条蛇做出选择之后它不是最小值,那么它尽管吃,因为下一个做出选择的蛇一定比它死得更快(因为做差后能力值更小)。

    如果它是最小值呢?那么这时候它就预知未来,让蛇们失去理智互吃,直到出现一条蛇做出选择之后不是最小值(或者没有蛇了),这条蛇一定是会吃的;根据这个过程进行的步数的奇偶性进行分类讨论,决定它是否吃,如果不吃就结束,如果吃也会在它下一条做出决定的蛇结束。

    这样这道题就做完了。

    这个做法妙就妙在:它没有把蛇们失去理智互吃的全过程搞出来,而是通过我们只关心最终的正确结果而设计的算法,在可以得到正确结果的时候return,避免了后面可能出现的问题。


    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cassert>
    #define N 1000005
    #define mp(x,y) make_pair(x,y)
    int n;
    pair<int,int> a[N],b[N];
    int ah,at,bh,bt;
    bool empty(){return !(ah<=at || bh<=bt);}
    pair<int,int> gmin(){
    	if (ah<=at && a[ah]<b[bt] || bh>bt)
    		return a[ah];
    	return b[bt];
    }
    pair<int,int> pop_front(){
    	if (ah<=at && a[ah]<b[bt] || bh>bt)
    		return a[ah++];
    	return b[bt--];
    }
    pair<int,int> pop_back(){
    	if (ah<=at && a[at]>b[bh] || bh>bt)
    		return a[at--];
    	return b[bh++];
    }
    pair<int,int> doit1(){
    	pair<int,int> p=pop_front(),q=pop_back(),r;
    //	printf("(%d,%d) eats (%d,%d)
    ",q.first,q.second,p.first,p.second);
    	r.first=q.first-p.first;
    	r.second=q.second;
    	return r;
    }
    void doit2(pair<int,int> &r){
    	pair<int,int> q=pop_back();
    	r.first=q.first-r.first;
    	r.second=q.second;
    }
    int work(){
    	int ans=n,i=1;
    	ah=1,at=n;
    	bh=1,bt=0;
    	for (;i<n;++i){
    		pair<int,int> r=doit1();
    		if (r<gmin() && !empty()){
    			int tmp=1;
    			for (++i;i<n;++i){
    				doit2(r);
    				tmp++;
    				if (r>gmin() && !empty()){
    					if (tmp&1^1)
    						return ans;
    //					assert(0);这个assert是假的,因为可能会出现值相同编号不同的问题。
    					return ans-1;
    				}
    			}
    			if (tmp&1^1)
    				return ans;
    			return ans-1;
    		}
    		else{
    			ans--;
    			b[++bt]=r;
    //			printf("(%d,%d)
    ",r.first,r.second);
    		}
    	}
    	return ans;
    }
    int main(){
    //	freopen("in.txt","r",stdin);
    //	freopen("out.txt","w",stdout);
    	freopen("snakes.in","r",stdin);
    	freopen("snakes.out","w",stdout);
    	int T;
    	scanf("%d%d",&T,&n);
    	for (int i=1;i<=n;++i)
    		scanf("%d",&a[i].first),a[i].second=i;
    	printf("%d
    ",work());
    	T--;
    	while (T--){
    		int k;
    		scanf("%d",&k);
    		for (int i=1;i<=k;++i){
    			int x,y;
    			scanf("%d%d",&x,&y);
    			a[x].first=y;
    		}
    		printf("%d
    ",work());
    	}
    	return 0;	
    }
    
  • 相关阅读:
    2021年4月1日
    2021年3月31日
    2021年3月30日
    2021年3月29日
    2021年3月27日
    2021年3月26日
    2021年3月25日
    人件集阅读笔记03
    2020年3月24日
    构建之法阅读笔记02
  • 原文地址:https://www.cnblogs.com/jz-597/p/13955614.html
Copyright © 2020-2023  润新知