并不对劲的CF1236D&E:Alice&Doll&UnfairGame

CF1236D Alice&Doll

题目描述

有一个机器人在一个\(n\times m\)的有\(k\)个障碍网格上移动,上北下南左西右东。
它一开始在第一行第一列,面朝东边。它在每个格子上可以右转一次或不右转,然后会向面向的方向走一步。
问能不能将所有不是障碍的格子都走恰好一遍。\(n,m,k\leq10^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('\n');return;}
	if(x<0)putchar('-'),x=-x;
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('\n');
}
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)log\space 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('\n');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('\n');
    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;
}
posted @ 2019-10-22 15:14  echo6342  阅读(335)  评论(0编辑  收藏  举报