9.18

9.18

凄凄惨惨戚戚——60送走大家ak

我想到的:
报数m-1 必然是必败态,那么只要自己在[now+1,now+k]中有一个必胜态则必胜,全是必败态则必败
没想到的:
dp。。。设dp[i][j]表示第i只animal报到j数字的胜利状态 1(win)
然后要倒着推,当前这个的状态由后面 [now+1,now+k]决定,我们只需记一个后缀数组
用suf[now+1]-suf[min(m,k+1)+1]即使当前的答案

(1) 没有硝烟的战争 ——dp

#include <queue>
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <utility>
#include <iostream>
#include <algorithm>

using namespace std;
const int N=5005;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}
int n,m,k,a[N];
int dp[N][N];//第i个报到j == 1(win) 
int nxt[N],suf[N][N];//后缀的dp数组 

int main() {
	n=read();m=read();k=read();
	for(int i=1;i<=n;i++) {
		a[i]=read();
		dp[i][m-1]=0;//lose 
		nxt[i]=i+1;
	}
	nxt[n]=1;
	for(int i=m-1;i;i--) {
		for(int j=n;j>=1;j--) {
			if(suf[nxt[j]][i+1]-suf[nxt[j]][min(i+k,m)+1]) dp[j][i]=1;
			if(a[j]!=a[nxt[j]]) dp[j][i]^=1;
			suf[j][i]=suf[j][i+1]+dp[j][i];
		}
	}
	for(int i=1;i<n;i++)
		printf("%d ",(suf[i][1]-suf[i][1+k])?a[i]:a[i]^1);//[1,k]有一个必胜态则自己win 
	printf("%d\n",(suf[n][1]-suf[n][1+k])?a[n]:a[n]^1);
	return 0;
}


(2)秘密通道 ——最短路

呃呃呃,60的原因。。。忘了可以在这开一枪跑到墙边再穿越

正解就是连边最短路,第一种就是每一个格子向他周围四个方向连一条长度 为 1 的边。 第二种就是每一个格子向他上下左右的第一堵墙连一 条长度为格子与最近的墙距离的边。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <algorithm>

using namespace std;
const int N=505;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}
int n,m;
char mp[N][N];
struct node{
	int x,y,d;
	node(){}
	node(int x_,int y_,int d_):x(x_),y(y_),d(d_){}
	bool operator < (const node &a) const {
		return d>a.d;
	} 
};
int stx,sty;
int ex,ey;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
bool vis[N][N];
int dis[N][N];
priority_queue<node>q;
int main() {
	n=read();m=read();
	for(int i=1;i<=n;i++)	
		scanf("%s",mp[i]+1);
	memset(dis,0x3f,sizeof(dis));
	for(int i=1;i<=n;i++)	
		for(int j=1;j<=m;j++) {
			if(mp[i][j]=='C') 
				stx=i,sty=j;
			else if(mp[i][j]=='F') 	
				ex=i,ey=j;
		}
	q.push(node(stx,sty,0));
	dis[stx][sty]=0;
	while(q.size()) {
		int x=q.top().x,y=q.top().y;q.pop();
		if(vis[x][y]) continue;
		vis[x][y]=1;
		
		int xx,yy,lx=x,rx=x,ly=y,ry=y;
		int near=0x3f3f3f3f;
		xx=x;
		while(xx<n&&mp[xx+1][y]!='#') xx++;
		if(mp[xx+1][y]=='#') near=min(near,xx-x),rx=xx;
		xx=x;
		while(xx>1&&mp[xx-1][y]!='#') xx--;
		if(mp[xx-1][y]=='#') near=min(near,x-xx),lx=xx;
		yy=y;
		while(yy>1&&mp[x][yy-1]!='#') yy--;
		if(mp[x][yy-1]=='#') near=min(near,y-yy),ly=yy;
		yy=y;
		while(yy<m&&mp[x][yy+1]!='#') yy++;
		if(mp[x][yy+1]=='#') near=min(near,yy-y),ry=yy;
		
		near++;
		if(dis[lx][y]>dis[x][y]+near) 
			dis[lx][y]=dis[x][y]+near,q.push(node(lx,y,dis[lx][y]));
		if(dis[rx][y]>dis[x][y]+near) 
			dis[rx][y]=dis[x][y]+near,q.push(node(rx,y,dis[rx][y]));
		if(dis[x][ly]>dis[x][y]+near) 
			dis[x][ly]=dis[x][y]+near,q.push(node(x,ly,dis[x][ly]));
		if(dis[x][ry]>dis[x][y]+near) 
			dis[x][ry]=dis[x][y]+near,q.push(node(x,ry,dis[x][ry]));
		
		for(int i=0;i<4;i++) {
			int xx=x+dx[i],yy=y+dy[i];
			if(xx<1||yy<1||yy>m||xx>n||mp[xx][yy]=='#') continue;
			if(dis[xx][yy]>dis[x][y]+1)
				dis[xx][yy]=dis[x][y]+1,q.push(node(xx,yy,dis[xx][yy]));
		}
	}
	if(dis[ex][ey]==dis[0][0]) puts("nemoguce");
	else printf("%d\n",dis[ex][ey]);
	
	return 0;
}


(3)城市猎人——按秩合并并查集

见并查集

posted @ 2020-09-20 10:09  ke_xin  阅读(37)  评论(0编辑  收藏  举报