码迷,mamicode.com
首页 > 其他好文 > 详细

并不对劲的CF1349B&C:Game of Median Life

时间:2020-05-13 23:43:33      阅读:123      评论:0      收藏:0      [点我收藏+]

标签:vector   它的   lin   没有   clu   ++   utc   ack   putchar   

CF1349B Orac and Medians

题目描述

\(n\)个数,\(a_1,a_2,...,a_n\)
该题中\(m\)个数的中位数的定义是:将这\(m\)个数排序后,排在第\(\lfloor \frac{m+1}{2}\rfloor\)的数。
可以进行的操作是:选一个区间\([l,r]\),将\(a_l,a_{l+1},...,a_r\)都变成\(a_l,a_{l+1},...,a_r\)的中位数。
给出\(a_1,...,a_n\)\(k\),问能否把所有数都变成\(k\)
\(n\leq 10^5;a_1,...,a_n,k\leq 10^9\)

一行题解

存在长度不少于2且区间内大于等于\(k\)的数的个数多于小于\(k\)的数的个数的区间。

题解

首先,如果\(k\)\(a_1,...,a_n\)中没出现过,就肯定不行;如果只有一个数而且和\(k\)相等,就肯定行。
一次“操作”可以把相邻两个数都变为它们之中较小的那个(称为“第一招”),也可以把有两个数相等的相邻的三个数变成那两个数的值(称为“第二招”)。
对于区间\([l,r](l<r)\),如果区间中位数大于等于\(k\)
(1)\(a_l,...,a_r\)中没有\(k\)\(k\)会出现在\(l\)左侧或\(r\)右侧,一次操作把\(a_l,...,a_r\)都变成大于\(k\)的数,用“第二招”可以使与\(k\)相邻的地方出现多个比\(k\)大的数,再用“第一招”可以把这些大于\(k\)的数都变成\(k\),再用“第二招”把所有数都变成\(k\)
(2)\(a_l,...,a_r\)中有\(k\):如果这些数的中位数就是\(k\),直接把它们变成\(k\),再用“第二招”把所有数变成\(k\);如果中位数大于\(k\),会发现\(k\)的某一侧的中位数也是大于等于\(k\),就和(1)相同。
所以“存在一个长度不少于2的区间中位数大于等于\(k\)”是“能把所有数变成\(k\)”的充分条件。
当不存在不少于2的区间中位数大于等于\(k\)时,任何一个区间的中位数都小于\(k\),所以任何操作都只会把一些数变成小于\(k\)的数,不能把所有数变成\(k\)。所以“存在一个长度不少于2的区间中位数大于等于\(k\)”是“能把所有数变成\(k\)”的必要条件。
所以判断“存在一个长度不少于2的区间中位数大于等于\(k\)”就行。
“区间中位数大于等于\(k\)”等价于“区间大于等于\(k\)的数多于小于\(k\)的数”,等价于“区间大于等于\(k\)的数的个数减小于\(k\)的数的个数大于0”。
把“大于等于\(k\)的数”看成1,“小于\(k\)的数”看成-1,判断前缀和的正负。

代码

#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‘);
}
int t,n,k,a[maxn],b[maxn];
int main()
{
	t=read();
	while(t--)
	{
		n=read(),k=read();int jud1=0;
		rep(i,1,n){a[i]=read();if(a[i]==k)jud1=1;}
		if(!jud1){puts("no");continue;}
		if(n==1){puts("yes");continue;}
		rep(i,1,n){if(a[i]>=k)b[i]=1;else b[i]=-1;}
		rep(i,1,n)b[i]+=b[i-1];
		int mn=0;jud1=0;
		rep(i,2,n)
		{
			mn=min(mn,b[i-2]);
			if(b[i]-mn>0){jud1=1;break;}
		}
		puts(jud1?"yes":"no");
	}
	return (~(0-0)+1);
}

CF1349C Orac and Game of Life

题目描述

有一个\(n\times m\)的网格,每个格有一个0或1的数。
“好”的格的定义为:该格正上、正下、正左、正右与它相邻的格上的数都与它不同。
每操作一次,会把所有“好”的格上的数异或1,不是“好”的格上的数不变。
\(t\)组询问,每次给出\(x,y,k\),问\(k\)次操作后在\((x,y)\)格上的数。
\(n,m\leq 1000;t\leq 10^5\)

题解

对于一个“好”的格,它旁边的那个跟它数一样的格在操作后会跟它一起变,所以“好”的格一直都是“好”的。
对于一个不“好”的格,如果有一个与它相邻的格子是“好”的,那么这次操作它不会变,与它相邻的“好”格子会变,它们在这场操作后数相同,原来不“好”的格会变成“好”格。
所以,对于“好”格,\(k\)次操作后格上的数会异或上\(k\)个1;对于不“好”格,\(k\)小于它到离它最近的“好”格的距离它的数就不变,\(k\)大于等于它到离它最近的“好”格的距离它就异或上\(k-距离\)个1。

代码

#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 1007 
using namespace std;
LL read()
{
	LL 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‘);
}
int n,m,t,dis[maxn][maxn],qx[maxn*maxn],qy[maxn*maxn],hd,tl;
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
char s[maxn][maxn];
inline int in(int x,int y){if(1<=x&&x<=n&&1<=y&&y<=m)return 1;return 0;} 
int main()
{
	n=read(),m=read(),t=read();hd=1;
	rep(i,1,n){scanf("%s",s[i]+1);}
	rep(i,1,n)rep(j,1,m)
	{
		int yes=0;
		rep(k,0,3)
		{
			int nx=i+dx[k],ny=j+dy[k];
			if(in(nx,ny)&&s[nx][ny]==s[i][j]){yes=1;break;}
		}
		if(yes)++tl,qx[tl]=i,qy[tl]=j;
		else dis[i][j]=-1;
	}
	while(hd<=tl)
	{
		int ux=qx[hd],uy=qy[hd];hd++;
		rep(k,0,3)
		{
			int nx=ux+dx[k],ny=uy+dy[k];
			if(in(nx,ny)&&dis[nx][ny]==-1){dis[nx][ny]=dis[ux][uy]+1,tl++,qx[tl]=nx,qy[tl]=ny;} 
		}
	}
	if(tl){rep(i,1,n)rep(j,1,m)if(dis[i][j]==-1)return 0;}
	while(t--)
	{
		int x=read(),y=read();LL k=read();
		if(!tl||k<(LL)dis[x][y])putchar(s[x][y]),putchar(‘\n‘); 
		else write((s[x][y]-‘0‘)^((k-(LL)dis[x][y])&1ll));
	}
	return (~(0-0)+1);
}

一些感想

小号也能打div1啦!
想做个拿猎虫打龙蚀虫的视频。

并不对劲的CF1349B&C:Game of Median Life

标签:vector   它的   lin   没有   clu   ++   utc   ack   putchar   

原文地址:https://www.cnblogs.com/xzyf/p/12884827.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!