zoukankan      html  css  js  c++  java
  • CF625E Frog Fights

    (n)只青蛙在一个长度为(m)的环上打架;每只青蛙有一个初始位置(p_i),和一个跳跃数值(a_i)。从(1)号青蛙开始按序号循环行动,每次若第(i)只青蛙行动,则它会向前跳 (a_i)个格子,撞飞它遇见的所有青蛙,包括终点格子上的,之后它的(a_i)减少等同于撞飞的青蛙只数,若(a_i<0),它不会移动。求最后剩下的所有青蛙的编号。(nleq 10^5,mleq 10^9)(p)互不不同


    这类问题就往相对位置的方向想吧,,,

    在第一次有青蛙撞飞其他青蛙之前,他们的相对位置都是不变的。所以考虑优化最朴素的模拟,即维护出第一次撞飞别人是什么时候以及哪只青蛙撞。所以一个优化的算法就是撞飞一只青蛙之后重新计算所有青蛙的位置。又由于每个青蛙只需要注意它正前方的那只,所以我们可以做一个链表来维护青蛙的相对位置。这样复杂度还是很高。但可以发现撞飞别人以后仍然有很多青蛙的相对位置没有变。如果我们每次都通过(初始距离之差/a之差)来计算青蛙相撞的时间,当某只青蛙撞完别人并且a减1之后,我们仍然用这个公式算就会有误差。假设这只青蛙在(t)时刻撞了别人,可以发现我们让它的位置往前挪(t)个单位就可以消除这个误差。所以我们就有一个新的算法,即每次相撞后修改一下撞击者的位置。这样就是(O(nlogn))了。

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define cn const
    #define gc getchar()
    #define fp(i,a,b) for(rg int i=(a),ed=(b);i<=ed;++i)
    #define fb(i,a,b) for(rg int i=(a),ed=(b);i>=ed;--i)
    #define mp make_pair
    using namespace std;
    typedef cn int cint;
    typedef pair<int,int> pr;
    il int rd(){
    	rg int x(0),f(1); rg char c(gc);
    	while(c<'0'||'9'<c){if(c=='-')f=-1;c=gc;}
    	while('0'<=c&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=gc;
    	return x*f;
    }
    cint maxn=1e5+10,inf=0x3f3f3f3f;
    int n,m,pre[maxn],nxt[maxn];
    set<pr> st;
    struct frog{int p,a,id;}a[maxn];
    il bool cmp(cn frog &a,cn frog &b){return a.p<b.p;}
    il bool cmp2(cn frog &a,cn frog &b){return a.id<b.id;}
    il int calc(int x,int y){
    	frog p=a[x],q=a[y];
    	rg int res=0;
    	if(x<y){
    		rg int tmp=p.p,now=tmp+p.a,now2=q.p;
    		p.p=(p.p+p.a-1)%m+1,res=1;
    		if(now2<tmp)now2+=m;
    		if(tmp<=now2&&now2<=now)return 1;
    	}
    	rg int dis=(q.p-p.p+m)%m,dec=p.a-q.a;
    	if(dec<=0)return inf;
    	return res+(dis+dec-1)/dec;
    }
    int main(){
    	n=rd(),m=rd();
    	fp(i,1,n)a[i].p=rd(),a[i].a=rd(),a[i].id=i;
    	sort(a+1,a+1+n,cmp);
    	pre[a[1].id]=a[n].id,nxt[a[1].id]=a[2].id,nxt[a[n].id]=a[1].id,pre[a[n].id]=a[n-1].id;
    	fp(i,2,n-1)pre[a[i].id]=a[i-1].id,nxt[a[i].id]=a[i+1].id;
    	sort(a+1,a+1+n,cmp2);
    	fp(i,1,n)st.insert(mp(calc(i,nxt[i]),i));
    	int fl=0;
    	while(st.size()){
    		set<pr>::iterator it=st.begin();
    		if(it->first==inf)break;
    		rg int i=it->second,tem=it->first;
    		st.erase(it);
    		st.erase(mp(calc(nxt[i],nxt[nxt[i]]),nxt[i]));
    		st.erase(mp(calc(pre[i],i),pre[i]));
    		--a[i].a,a[i].p=(a[i].p+tem-1)%m+1;
    		pre[nxt[nxt[i]]]=i,nxt[i]=nxt[nxt[i]];
    		st.insert(mp(calc(pre[i],i),pre[i]));
    		st.insert(mp(calc(i,nxt[i]),i));
    	}
    	printf("%d
    ",st.size());
    	for(auto &x:st)printf("%d ",x.second);
    	return 0;
    }
    
  • 相关阅读:
    Android中开发习惯
    Activity、Window和View三者间的关系有一定的见解
    Android底层有一定的认识,研究过相关的Android源码
    安卓工程的启动过程
    OAuth2认证有一定的了解
    屏幕适配经验
    NOIP模拟赛14
    NOIP模拟赛13
    NOIP模拟赛12
    NOIP模拟赛11
  • 原文地址:https://www.cnblogs.com/akura/p/14314749.html
Copyright © 2011-2022 走看看