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


    CF1349B Orac and Medians

    题目描述

    (n)个数,(a_1,a_2,...,a_n)
    该题中(m)个数的中位数的定义是:将这(m)个数排序后,排在第(lfloor frac{m+1}{2} floor)的数。
    可以进行的操作是:选一个区间([l,r]),将(a_l,a_{l+1},...,a_r)都变成(a_l,a_{l+1},...,a_r)的中位数。
    给出(a_1,...,a_n)(k),问能否把所有数都变成(k)
    (nleq 10^5;a_1,...,a_n,kleq 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('
    ');return;}
    	if(x<0)putchar('-'),x=-x;
    	while(x)ch[++f]=x%10+'0',x/=10;
    	while(f)putchar(ch[f--]);
    	putchar('
    ');
    }
    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 imes m)的网格,每个格有一个0或1的数。
    “好”的格的定义为:该格正上、正下、正左、正右与它相邻的格上的数都与它不同。
    每操作一次,会把所有“好”的格上的数异或1,不是“好”的格上的数不变。
    (t)组询问,每次给出(x,y,k),问(k)次操作后在((x,y))格上的数。
    (n,mleq 1000;tleq 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('
    ');return;}
    	if(x<0)putchar('-'),x=-x;
    	while(x)ch[++f]=x%10+'0',x/=10;
    	while(f)putchar(ch[f--]);
    	putchar('
    ');
    }
    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('
    '); 
    		else write((s[x][y]-'0')^((k-(LL)dis[x][y])&1ll));
    	}
    	return (~(0-0)+1);
    }
    

    一些感想

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

  • 相关阅读:
    负载平衡问题
    [SHOI2008]堵塞的交通traffic
    Bzoj3626 [LNOI2014]LCA
    [TJOI2015]旅游
    [SCOI2016]美味
    [AH/HNOI2017]单旋
    Luogu3613 睡觉困难综合征
    [SCOI2007]降雨量
    [SCOI2005]王室联邦
    HAOI2011 problem a
  • 原文地址:https://www.cnblogs.com/xzyf/p/12884827.html
Copyright © 2020-2023  润新知