并不对劲的CF1365D&E&F: Solve The Maximum Subsequence Again

CF1365D: Solve The Maze

题目大意

有一个\(n\times m\)的迷宫,每个位置上可能是空地或墙,位置\((n,m)\)一定是空地。
有些不是\((n,m)\)的空地上站了人,人有好人和坏人。人能往上下左右没墙的地方走。
判断能否把若干个不站人的空地(包括\((n,m)\))变成墙,使所有好人能走到\((n,m)\)且所有坏人走不到\((n,m)\)
\(数据组数\leq 100;n,m\leq 50;\)

题解

如果把所有与坏人相邻且没站人的空地变成墙,就能使所有坏人走不到终点。
除此之外的任何一种方案都不会让这种方案中不能走到终点的位置能走到终点。所以用这种方案就行。

代码
#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 maxn 57
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)
{
	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;
}
char mp[maxn][maxn];
int n,m,vis[maxn][maxn],gx[maxn*maxn],gy[maxn*maxn],cntg;
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
int no(int x,int y)
{
	if(x<1||x>n||y<1||y>m)return 1;
	if(mp[x][y]=='#'||mp[x][y]=='B'||mp[x+1][y]=='B'||mp[x][y+1]=='B'||mp[x-1][y]=='B'||mp[x][y-1]=='B')return 1;
	return 0;
}
void work(int x,int y)
{
	if(no(x,y))return;vis[x][y]=1;
	rep(i,0,3)if(!vis[x+dx[i]][y+dy[i]])work(x+dx[i],y+dy[i]);
}
int main()
{
	int t=read();
	rep(i,0,50)mp[i][0]=mp[0][i]='.';
	rep(x,1,t)
	{
		n=read(),m=read();cntg=0;
		rep(i,1,n)scanf("%s",mp[i]+1);
		rep(i,1,n)rep(j,1,m){vis[i][j]=0;if(mp[i][j]=='G')cntg++,gx[cntg]=i,gy[cntg]=j;}
		rep(i,0,m)mp[n+1][i]='.';
		rep(i,0,n)mp[i][m+1]='.';
		work(n,m);int yes=1;
		rep(i,1,cntg)if(!vis[gx[i]][gy[i]]){yes=0;break;}
		puts(yes?"Yes":"No");
	}
	return 0;
}

CF1365E: Maximum Subsequence Value

题目大意

\(n\)个数\(a_1,...,a_n\),从中选出若干个数使它们的价值最大。
\(x\)个数的价值:当且仅当这\(x\)个数中有至少\(max(1,x-2)\)个在二进制的\(2^k\)位为1,价值在二进制的\(2^k\)位为1。
\(n\leq 500;a_i\leq 10^{18};\)

题解

\(x\leq 3\)时,只要\(x\)个数中某一位有1,价值在这一位就是1。所以价值是它们的或和。
对于\(n\)个数,假设一开始都选,每次删一个数。
剩下的数超过3个,删掉一个数\(a_i\)时,对于\(a_i\)在这一位为1的二进制位,该位为1的数的个数 和 总数 的差不变,价值在这些位上不会变化;对于\(a_i\)在这一位上位0的二进制位,价值在这些位上可能由0变成1。
所以在删数的过程中,价值不会减少。找三个或和最大的数。

代码
#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 507
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(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;
LL a[maxn],ans;
int main()
{
	n=read();
	rep(i,1,n)a[i]=read(),ans=max(a[i],ans);
	rep(i,1,n)rep(j,i+1,n){ans=max(a[i]|a[j],ans);rep(k,j+1,n)ans=max(ans,a[i]|a[j]|a[k]);}
	write(ans); 
	return 0;
}

CF1365F: Swaps Again

题目大意

有两个长度为\(n\)的数组\(a_1,...,a_n\)\(b_1,...,b_n\)
可以进行的操作是选一个数\(k\),交换\(a_1,...,a_k\)\(a_{n-k+1},...,a_n\)
判断\(a_1,...,a_n\)能否通过若干次操作变成\(b_1,...,b_n\)
\(数据组数\leq 500;n\leq 500;\)

题解

\(n\)为奇数时,正中间的那个数换不走,如果\(a\)\(b\)在正中间不同就一定不行。
题目中描述的操作相当于依次交换\(a_1和a_{n-k+1}\)\(a_2和a_{n-k+2}\)、…、\(a_k和a_n\),对于操作涉及的数\(a_x\),它被换到了位置\(n-k+x\)
对于某次操作涉及的\(a_x\)\(a_y\),若\(y=n-x+1\),则\(a_x\)被换到了\(n-k+x\)\(a_y\)被换到了\(n-k+y\)\(n-k+x=n-(n-k+y)+1\)
交换\(a_x\)\(a_{n-x+1}\)的方法是依次选\(x,1,x\)进行操作。
可以把\(a_1,...,a_n\)分成若干个无序对\((a_i,a_{n-i+1})\),这些无序对组成的无序集不会因操作变化。
所以,如果\(a\)\(b\)划分出的无序对的无序集不同,\(a\)就一定不能通过操作变成\(b\)
当它们的无序集相同时,考虑构造一种操作方法使它们相同:
从中间向两边依次考虑,对于位置\(x\)\(n-x+1\),设与无序对\((b_x,b_{n-x+1})\)相同的是\((a_y,a_{n-y+1})\),则依次选\(y,x\)进行操作,这样不会改变中间已经排好的部分。
所以“\(a\)\(b\)划分出的无序对的无序集相同”是“\(a\)能操作若干次变成\(b\)”的充要条件。

代码
#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 maxn 507
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
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)
{
	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],b[maxn],li;
pii pa[maxn],pb[maxn];
int main()
{
	int t=read();
	while(t--)
	{
		n=read();
		rep(i,1,n)a[i]=read();
		rep(i,1,n)b[i]=read();
		int li=n/2;
		rep(i,1,li){pa[i]=mp(a[i],a[n-i+1]);if(pa[i].fi<pa[i].se)swap(pa[i].fi,pa[i].se);}
		rep(i,1,li){pb[i]=mp(b[i],b[n-i+1]);if(pb[i].fi<pb[i].se)swap(pb[i].fi,pb[i].se);}
		if(n&1){li++,pa[li]=mp(a[n/2+1],0),pb[li]=mp(b[n/2+1],0);}
		sort(pa+1,pa+li+1),sort(pb+1,pb+li+1);
		int no=0;
		rep(i,1,li)if(pa[i]!=pb[i]){no=1;break;}
		puts(no?"No":"Yes");
	}
	return 0;
}
posted @ 2020-06-08 10:59  echo6342  阅读(361)  评论(0编辑  收藏  举报