zoukankan      html  css  js  c++  java
  • 并不对劲的CF1236D&E:Alice&Doll&UnfairGame

    CF1236D Alice&Doll

    题目描述

    有一个机器人在一个(n imes m)的有(k)个障碍网格上移动,上北下南左西右东。
    它一开始在第一行第一列,面朝东边。它在每个格子上可以右转一次或不右转,然后会向面向的方向走一步。
    问能不能将所有不是障碍的格子都走恰好一遍。(n,m,kleq10^5)

    题解

    会发现每个格只能右转一次,所以最后走出的路径大概这样:

    -------------------
     *                |
     *                |
     |----------*     |
     |   *-----|      |
    *------------------                 
    

    手动模拟这个过程就行。
    注意考虑在一开始就拐弯的情况,不然会FST。

    代码

    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #define LL long long
    #define rep(i,x,y) for(int i=(x);i<=(y);++i)
    #define dwn(i,x,y) for(int i=(x);i>=(y);--i)
    #define view(u,k) for(int k=fir[u];~k;k=nxt[k])
    #define maxn 100007
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)&&ch!='-')ch=getchar();
    	if(ch=='-')f=-1,ch=getchar();
    	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return x*f;
    }
    void write(int x)
    {
    	char ch[20];int f=0;
    	if(!x){putchar('0'),putchar('
    ');return;}
    	if(x<0)putchar('-'),x=-x;
    	while(x)ch[++f]=x%10+'0',x/=10;
    	while(f)putchar(ch[f--]);
    	putchar('
    ');
    }
    vector<int>nd[2][maxn];
    int p[2][maxn],n,m,k,mx[4],now,f;
    bool cmpy(int x,int y){return p[1][x]<p[1][y];}
    bool cmpx(int x,int y){return p[0][x]<p[0][y];} 
    int getp(int rc,int k,int x,int f)
    {
    	if(nd[rc][k].size()==0)return -1;
    	int l=0,r=nd[rc][k].size()-1,ans=-1;
    	if(f==0&&p[rc^1][nd[rc][k][l]]>x)return -1;
    	if(f==1&&p[rc^1][nd[rc][k][r]]<x)return -1;
    	while(l<=r)
    	{
    		int mid=l+r>>1;
    		if((!f&&p[rc^1][nd[rc][k][mid]]<=x)||(f&&p[rc^1][nd[rc][k][mid]]>=x))
    		{
    			if(!f)ans=max(ans,mid),l=mid+1;
    			else ans=ans==-1?mid:min(ans,mid),r=mid-1;
    		}
    		else 
    		{
    			if(!f)r=mid-1;
    			else l=mid+1;
    		}
    	}
    	if(ans!=-1)ans=nd[rc][k][ans];
    	return ans;
    }
    int main()
    {
    	n=read(),m=read(),k=read();mx[0]=m,mx[1]=n,mx[2]=mx[3]=1;
    	rep(i,1,k){p[0][i]=read(),p[1][i]=read(),nd[0][p[0][i]].push_back(i),nd[1][p[1][i]].push_back(i);if(p[0][i]==1&&p[1][i]==2)f=1;}
    	rep(i,1,n)sort(nd[0][i].begin(),nd[0][i].end(),cmpy); 
    	rep(i,1,m)sort(nd[1][i].begin(),nd[1][i].end(),cmpx); 
    	int px=1,py=1;LL sum=(LL)n*m-1;
    	if(m==1)f=1;
    	if(f)now=1,mx[0]=1;
    	while(1)
    	{
    		int pre=now-1;if(pre==-1)pre=3;
    		if(now==0)
    		{
    			int x=getp(0,px,py,1);
    			if(x!=-1)x=min(mx[now],p[1][x]-1);
    			else x=mx[now];
    			if(x==py)break;
    			sum-=(LL)(x-py);
    			mx[pre]=px+1,py=x;
    		}
    		else if(now==1)
    		{
    			int x=getp(1,py,px,1);
    			if(x!=-1)x=min(mx[now],p[0][x]-1); 
    			else x=mx[now];
    			if(x==px)break;
    			sum-=(LL)(x-px);
    			mx[pre]=py-1,px=x;
    		}
    		else if(now==2)
    		{
    			int x=getp(0,px,py,0);
    			if(x!=-1)x=max(mx[now],p[1][x]+1);
    			else x=mx[now];
    			if(x==py)break;
    			sum-=(LL)(py-x);
    			mx[pre]=px-1,py=x; 
    		}
    		else 
    		{
    			int x=getp(1,py,px,0);
    			if(x!=-1)x=max(mx[now],p[0][x]+1);
    			else x=mx[now];
    			if(x==px)break;
    			sum-=(LL)(px-x);
    			mx[pre]=py+1,px=x; 
    		}
    		now=(now+1)%4;
    	}
    	if(sum==(LL)k)puts("Yes");
    	else puts("No");
    	return (0-0);
    }
    

    CF1236E Alice&UnfairGame

    题目描述

    A和B两个人在玩游戏。有编号为1到(n)(n)个箱子按编号顺序排成一排,有一个箱子里有东西。
    游戏要进行(m)轮,每轮的流程是:A先把东西移动到和它相邻的箱子里,然后B猜哪个箱子里有东西。一旦B猜中了,游戏就会结束,并且B获胜。
    若游戏进行完了第(m)轮,则A还可以把东西移动到和它相邻的箱子里一次,之后A胜利。
    已知(n,m),和B在每一轮会猜测的箱子编号(a_1,...,a_m),问有多少对((x,y))满足游戏开始前东西在(x)号箱子,游戏结束时东西在(y)号箱子,且A胜利。

    一行题解

    对于同一个起点,合法终点连续=>在有障碍物的平面上行走=>在某时刻走到某点的“人”的起点连续=>线段树维护区间加减

    题解

    这个人讲得很清楚。
    发现在A知道B的猜测序列时,除非(n=1),A总有办法赢。
    具体的方式是:从随便一个位置出发,如果这一轮B猜的是左边相邻的箱子就往右走或不走,右边同理,如果B猜的是当前箱子就往右或左走,如果都不是就往右或往左或不走。
    按这种移动方式,会发现从每个位置出发,能使A赢的结束位置一定是连续的。
    所以可以通过求从每个点出发能走到的使A赢的最左、最右位置。
    先考虑最右位置。
    假设从(x)出发,当前位置为(p),时刻为(t),那么为了尽可能往右走,应该当且仅当(a_t=p+1)时不会走,其他时候都会向右走。
    可以把这个过程看成在平面上行走:以时刻为横坐标,以位置为纵坐标,一个人一开始在((0,x))出发,对于每个时刻,如果他右上方没有障碍物就往右上走,反之往右走。
    这样是(O(n^2))的。
    考虑把所有“人”放在一块考虑:有(n)个人在平面上行走,(i)号人从((0,i))出发,每个人的走法和上面一样。
    发现人们走出的路径可能会合并,但不会交叉。也就是说,某时刻在某位置的人们的坐标是连续的,某时刻人们的坐标按编号是单调不降的。
    对于坐标为((i,a_i))的障碍物,会挡住走到((i-1,a_i-1))的“人”们。可以二分出这一段“人”的编号区间。在下一个时刻,除了这个编号区间的人以外,所有人纵坐标+1。
    可以用线段树维护当前人们走到的位置的纵坐标。
    注意人们不能走出去,因此可以设置((1,n+1),(2,n+1),...,(m,n+1))这些额外的障碍物。
    对于最左位置,可以看成把序列翻转后的最右位置。
    时间复杂度(O((n+m)logspace n))

    代码

    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<set>
    #include<stack>
    #include<vector>
    #define rep(i,x,y) for(register int i=(x);i<=(y);++i)
    #define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
    #define view(u,k) for(int k=fir[u];~k;k=nxt[k])
    #define LL long long
    #define maxn 100007
    #define ls (u<<1)
    #define rs (u<<1|1)
    #define mi ((l+r)>>1) 
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)&&ch!='-')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
        return x*f;
    }
    void write(LL x)
    {
        if(x==0){putchar('0'),putchar('
    ');return;}
        int f=0;char ch[20];
        if(x<0)putchar('-'),x=-x;
        while(x)ch[++f]=x%10+'0',x/=10;
        while(f)putchar(ch[f--]);
        putchar('
    ');
        return;
    }
    int n,a[maxn],m,ans[2][maxn];
    LL Ans;
    int mn[maxn<<2],mx[maxn<<2],mk[maxn<<2];
    void pu(int u){mn[u]=min(mn[ls],mn[rs]),mx[u]=max(mx[ls],mx[rs]);}
    void build(int u,int l,int r)
    {
    	mk[u]=0;
    	if(l==r){mx[u]=mn[u]=l;return;}
    	build(ls,l,mi),build(rs,mi+1,r),pu(u);return;
    }
    void mark(int u,int k){mn[u]+=k,mx[u]+=k,mk[u]+=k;}
    void pd(int u){if(mk[u])mark(ls,mk[u]),mark(rs,mk[u]),mk[u]=0;}
    void add(int u,int l,int r,int x,int y,int k)
    {
    	if(x<=l&&r<=y){mark(u,k);return;}
    	pd(u);
    	if(x<=mi)add(ls,l,mi,x,y,k);
    	if(y>mi)add(rs,mi+1,r,x,y,k);
    	pu(u);return;
    }
    int askl(int u,int l,int r,int x)//max,<x
    {
    	if(l==r)return mx[u]<x?l:l-1;
    	pd(u);
    	if(mn[rs]<x)return askl(rs,mi+1,r,x);
    	return askl(ls,l,mi,x);
    }
    int askr(int u,int l,int r,int x)//min,>x
    {
    	if(l==r)return mx[u]>x?l:l+1;
    	pd(u);
    	if(mx[ls]>x)return askr(ls,l,mi,x);
    	return askr(rs,mi+1,r,x);
    }
    int ask(int u,int l,int r,int x)
    {
    	if(x<=l&&r<=x){return mx[u];}
    	pd(u);
    	if(x<=mi)return ask(ls,l,mi,x);
    	return ask(rs,mi+1,r,x);
    }
    void work(int f)
    {
    	build(1,1,n);
    	rep(i,1,m+1)
    	{
    		int l2=askl(1,1,n,n),r2=n;
    		if(i<=m)
    		{
    			int l=askl(1,1,n,a[i]-1),r=askr(1,1,n,a[i]-1);
    			if(l+1<=r-1)add(1,1,n,l+1,r-1,-1);
    		}
    		mk[1]++;
    		if(l2+1<=r2)add(1,1,n,l2+1,r2,-1);
    	}
    	rep(i,1,n)ans[f][i]=ask(1,1,n,i);
    }
    int main()
    {
    	n=read(),m=read();
    	rep(i,1,m)a[i]=read();
    	work(0);
    	rep(i,1,m)a[i]=n-a[i]+1;
    	work(1);
    	reverse(ans[1]+1,ans[1]+n+1);
    	rep(i,1,n)ans[1][i]=n-ans[1][i]+1;
    	rep(i,1,n)Ans+=max(0ll,(LL)(ans[0][i]-ans[1][i]+1));
    	write(Ans);
    	return 0;
    }
    
  • 相关阅读:
    IE block my cookie in iframe
    error app/styles/components/iconfont.scss (Line 12: Invalid GBK character "xE5")
    angular4开发过程中遇到的问题和知识点记录
    博客
    009android初级篇之APP中使用系统相机相册等集成应用
    012android初级篇之Handler机制
    android studio win7开发环境
    001windows已遇到一个关键性问题 一分钟后自动重启
    008android初级篇之jni中数组的传递
    006android初级篇之jni数据类型映射
  • 原文地址:https://www.cnblogs.com/xzyf/p/11713734.html
Copyright © 2011-2022 走看看