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
",(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
",dis[ex][ey]);
return 0;
}
(3)城市猎人——按秩合并并查集
见并查集