中秋节模拟赛之冷月葬花魂(被虐瞎)

https://vijos.org/tests/5404825e48c5fcd4578b457a

果然蒟蒻还是蒟蒻。。

搜索不会,dp不会,模拟不会T_TT__T_T_T_TT_T_T_T_T_T_T

什么节奏啊这是。

 

t1:小岛的标号

模拟+bfs。。

用map被tle了1个点啊!坑啊,,rp低啊。。

90分滚粗。。。。

正解:建个trie。。然后在上面维护点的信息,,然后每个组的人员的编号连边,从“Xiaodao”的点作根bfs。。然后每个点的深度就是解。。。。。。。

#include <cstdio>

#include <cstring>

#include <cmath>

#include <string>

#include <iostream>

#include <algorithm>

#include <queue>

using namespace std;

#define rep(i, n) for(int i=0; i<(n); ++i)

#define for1(i,a,n) for(int i=(a);i<=(n);++i)

#define for2(i,a,n) for(int i=(a);i<(n);++i)

#define for3(i,a,n) for(int i=(a);i>=(n);--i)

#define for4(i,a,n) for(int i=(a);i>(n);--i)

#define CC(i,a) memset(i,a,sizeof(i))

#define read(a) a=getint()

#define print(a) printf("%d", a)

#define dbg(x) cout << #x << " = " << x << endl

#define printarr(a, n, m) rep(aaa, n) { rep(bbb, m) cout << a[aaa][bbb]; cout << endl; }

inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }

inline const int max(const int &a, const int &b) { return a>b?a:b; }

inline const int min(const int &a, const int &b) { return a<b?a:b; }



const int N=50005;



struct ED { int to, next; }e[N*20];

int cnt, ihead[N], q[N], front, tail, vis[N], d[N];

inline void add(const int &u, int &v) {

	e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v;

	e[++cnt].next=ihead[v]; ihead[v]=cnt; e[cnt].to=u;

}

int n, tot;

void bfs() {

	q[tail++]=1; vis[1]=1;

	int u, v;

	while(front!=tail) {

		u=q[front++]; if(front==N) front=0;

		for(int i=ihead[u]; i; i=e[i].next) if(!vis[v=e[i].to]) {

			vis[v]=1;

			d[v]=d[u]+1;

			q[tail++]=v; if(tail==N) tail=0;

		}

	}

}

const int Tcnt=1000005;

int T[Tcnt][55], id[Tcnt], sz;

void ins(char s[], int dt) {

	int len=strlen(s), now=0;

	rep(i, len) {

		int t;

		if(s[i]>='A' && s[i]<='Z') t=s[i]-'A'+27;

		else t=s[i]-'a'+1;

		if(T[now][t]) now=T[now][t];

		else now=T[now][t]=++sz;

	}

	id[now]=dt;

}

int ifind(char s[]) {

	int len=strlen(s), now=0;

	rep(i, len) {

		int t;

		if(s[i]>='A' && s[i]<='Z') t=s[i]-'A'+27;

		else t=s[i]-'a'+1;

		if(T[now][t]) now=T[now][t];

		else return 0;

	}

	return id[now];

}

char pr[40];

void dfs(int now, int t) {

	if(id[now]) {

		pr[t]='\0'; 

		int an=d[id[now]];

		printf("%s ", pr);

		if(an || !strcmp(pr, "Xiaodao")) printf("%d\n", an);

		else puts("undefined");

	}

	rep(i, 55) if(T[now][i]) {

		if(i<=26) pr[t]='a'+i-1;

		else pr[t]='A'+i-27;

		dfs(T[now][i], t+1);

	}

}

int main() {

	read(n);

	char str[30]="Xiaodao";

	ins(str, ++tot);

	for1(i, 1, n) {

		static int idd[5];

		for1(j, 1, 3) {

			scanf("%s", str);

			int t=ifind(str);

			if(!t) { ins(str, ++tot); idd[j]=tot;  }

			else idd[j]=t;

		}

		for1(j, 1, 3) for1(k, j+1, 3) add(idd[j], idd[k]);

	}

	bfs();

	dfs(0, 0);

	return 0;

}

 

t2:小岛的塔防游戏

裸暴力50分滚粗T_T

正解:

我们发现每个塔的攻击范围是一个正方形,,只不过是斜的45度。。

那么我们将整个图斜过来(图变成(n+m-1)边长的矩形,每个点(i,j)在这个新图上对应的点是(i-j+m,i+j-1),,很神奇是不是。。。自己画图。。)//upd:根本不用画图,其实这个就是按对角线剖分。。。

然后问题变为枚举每个点,然后询问在它的攻击范围内有多少个目标,最后排序后取k个

维护矩形我们用二维前缀和。。。(sum[i][j]表示(i,j)到(1,1)的和)

sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]

询问:

ask(x1, y1, x2, y2)=sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1]

自己理解。。

#include <cstdio>

#include <cstring>

#include <cmath>

#include <string>

#include <iostream>

#include <algorithm>

#include <queue>

using namespace std;

#define rep(i, n) for(int i=0; i<(n); ++i)

#define for1(i,a,n) for(int i=(a);i<=(n);++i)

#define for2(i,a,n) for(int i=(a);i<(n);++i)

#define for3(i,a,n) for(int i=(a);i>=(n);--i)

#define for4(i,a,n) for(int i=(a);i>(n);--i)

#define CC(i,a) memset(i,a,sizeof(i))

#define read(a) a=getint()

#define print(a) printf("%d", a)

#define dbg(x) cout << #x << " = " << x << endl

#define printarr(a, n, m) rep(aaa, n) { rep(bbb, m) cout << a[aaa][bbb]; cout << endl; }

inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }

inline const int max(const int &a, const int &b) { return a>b?a:b; }

inline const int min(const int &a, const int &b) { return a<b?a:b; }



const int N=1005;

int mp[N][N], a[N][N], sum[N<<1][N<<1], n, m, r, T, cnt, nn, mm;

char str[1005];

long long d[N*N], ans;



inline const bool cmp(const int &a, const int &b) { return a>b; }

inline const int X(const int &x, const int &y) { return x-y+m; }

inline const int Y(const int &x, const int &y) { return x+y-1; }



inline const int cal(const int &x, const int &y) {

	int x1=max(x-r, 1), y1=max(y-r, 1), x2=min(nn, x+r), y2=min(mm, y+r);

	return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];

}

int main() {

	read(n); read(m); read(T); read(r);

	for1(i, 1, n) {

		scanf("%s", str+1);

		for1(j, 1, m) {

			if(str[j]=='O') mp[i][j]=1;

			else if(str[j]=='X') mp[i][j]=2;

			if(mp[i][j]==1) {

				int x=X(i, j), y=Y(i, j);

				sum[x][y]=1;

			}

		}

	}

	nn=mm=n+m-1;

	for1(i, 1, nn) for1(j, 1, mm) sum[i][j]+=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1];

	for1(i, 1, n) for1(j, 1, m) if(mp[i][j]==0) {

		int x=X(i, j), y=Y(i, j);

		d[++cnt]=cal(x, y);

	}

	sort(d+1, d+1+cnt, cmp);

	long long ans=0;

	for1(i, 1, T) ans+=d[i];

	printf("%lld\n", ans);

	return 0;

}

 

t3:小岛的生日聚会

不忍吐槽,,我随便乱搞骗分骗了59分。。

什么节奏。。。

正解:还不会。听说是dp。。

 

t4:小岛的贪吃蛇

我存图bfs然后队列开不大,,然后wa。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

证明我是蒟蒻。。

我也想到头到尾的方法。。但是。。。我存的状态是整个图。。。。

。。。

正解:听说维护方向。。。但是维护方向怎么判可行啊。T_T难道是拓展的时候建个8×8的小图然后判么T_T

 

50分。。。。没判重。。

我们只需要维护蛇头,然后维护一个方向向量即可。

因为长度很短,我们可以考虑用二进制来存方向!(orzzzzzzzzzzzzzzz

我们两个位来存4种方向,然后每一次移动就直接f<<=2就能空出一个位置了。。

然后没判重只有50分。。

#include <cstdio>

#include <cstring>

#include <cmath>

#include <string>

#include <iostream>

#include <algorithm>

#include <queue>

using namespace std;

#define rep(i, n) for(int i=0; i<(n); ++i)

#define for1(i,a,n) for(int i=(a);i<=(n);++i)

#define for2(i,a,n) for(int i=(a);i<(n);++i)

#define for3(i,a,n) for(int i=(a);i>=(n);--i)

#define for4(i,a,n) for(int i=(a);i>(n);--i)

#define CC(i,a) memset(i,a,sizeof(i))

#define read(a) a=getint()

#define print(a) printf("%d", a)

#define dbg(x) cout << (#x) << " = " << (x) << endl

#define printarr(a, n, m) for1(aaa, 1, n) { for1(bbb, 1, m) cout << a[aaa][bbb] << '\t'; cout << endl; }

inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }

inline const int max(const int &a, const int &b) { return a>b?a:b; }

inline const int min(const int &a, const int &b) { return a<b?a:b; }

#define error(x) (!(x)?puts("error"):0)



const int N=22, Q=10000000, dx[]={-1, 1, 0, 0}, dy[]={0, 0, -1, 1}, PW=17;

int front, tail, n, m, l, mp[N][N], ALL;

struct dat { int x, y, d, f; }q[Q];

bool check(int f, int x) {

	f=((f<<2)|x)&ALL;

	int s1=0, s2=0;

	rep(i, l) {

		int now=(f>>(i<<1))&3;

		s1+=dx[now];

		s2+=dy[now];

		if(s1==0 && s2==0) return false;

	}

	return true;

}

void bfs() {

	front=tail=0; ++tail;

	while(front!=tail) {

		dat &t=q[front++]; if(front==Q) front=0;

		int x=t.x, y=t.y, dis=t.d;

		if(x==1 && y==1) { printf("%d\n", dis); return; }

		rep(i, 4) {

			int fx=dx[i]+x, fy=dy[i]+y;

			if(fx<1 || fy<1 || fx>n || fy>m || mp[fx][fy]) continue;

			if(!check(t.f, i)) continue;

			dat &t2=q[tail++]; if(tail==Q) tail=0;

			t2.x=fx;

			t2.y=fy;

			t2.d=dis+1;

			t2.f=((t.f<<2)|i)&ALL;

		}

	}

	puts("-1");

}

int main() {

	int cs=0;

	while(~scanf("%d%d%d", &n, &m, &l) && !(n==0 && m==0 && l==0)) {

		printf("Case %d: ", ++cs);



		CC(mp, 0);

		q[0].f=0;

		q[0].d=0;

		ALL=(1<<(l<<1))-1;



		int nx=getint(), ny=getint();

		q[0].x=nx, q[0].y=ny;

		int &f=q[0].f;

		rep(i, l-1) {

			int x=getint(), y=getint();

			if(x==nx-1) f|=(1<<(i<<1));

			else if(x==nx+1) f|=(0<<(i<<1));

			else if(y==ny-1) f|=(3<<(i<<1));

			else if(y==ny+1) f|=(2<<(i<<1));

			nx=x; ny=y;

		}

		int k=getint();

		while(k--) { int x=getint(), y=getint(); mp[x][y]=1; } 

		bfs();

	}

	return 0;

}

  

bfs的判重写在了出队那里,tle了n久,累觉无爱

#include <cstdio>

#include <cstring>

#include <cmath>

#include <string>

#include <iostream>

#include <algorithm>

#include <queue>

using namespace std;

#define rep(i, n) for(int i=0; i<(n); ++i)

#define for1(i,a,n) for(int i=(a);i<=(n);++i)

#define for2(i,a,n) for(int i=(a);i<(n);++i)

#define for3(i,a,n) for(int i=(a);i>=(n);--i)

#define for4(i,a,n) for(int i=(a);i>(n);--i)

#define CC(i,a) memset(i,a,sizeof(i))

#define read(a) a=getint()

#define print(a) printf("%d", a)

#define dbg(x) cout << (#x) << " = " << (x) << endl

#define printarr(a, n, m) for1(aaa, 1, n) { for1(bbb, 1, m) cout << a[aaa][bbb] << '\t'; cout << endl; }

inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }

inline const int max(const int &a, const int &b) { return a>b?a:b; }

inline const int min(const int &a, const int &b) { return a<b?a:b; }

#define error(x) (!(x)?puts("error"):0)



const int N=22, Q=5000000, dx[]={-1, 1, 0, 0}, dy[]={0, 0, -1, 1};

int front, tail, n, m, l, mp[N][N], ALL;

bool vis[N][N][18000];

struct dat { int x, y, d, f; }q[Q];

bool check(int f, int x) {

	f=(f<<2)|x;

	int s1=0, s2=0;

	rep(i, l) {

		int now=(f>>(i<<1))&3;

		s1+=dx[now];

		s2+=dy[now];

		if(s1==0 && s2==0) return false;

	}

	return true;

}

void bfs() {

	front=tail=0; ++tail;

	vis[q[0].x][q[0].y][q[0].f]=1;

	while(front!=tail) {

		dat &t=q[front++]; if(front==Q) front=0;

		int x=t.x, y=t.y, dis=t.d;

		if(x==1 && y==1) { printf("%d\n", dis); return; }

		rep(i, 4) {

			int fx=dx[i]+x, fy=dy[i]+y;

			if(fx<1 || fy<1 || fx>n || fy>m || mp[fx][fy] || vis[fx][fy][((t.f<<2)|i)&ALL]) continue;

			if(!check(t.f, i)) continue;

			dat &t2=q[tail++]; if(tail==Q) tail=0;

			t2.x=fx;

			t2.y=fy;

			t2.d=dis+1;

			t2.f=((t.f<<2)|i)&ALL;

			vis[fx][fy][t2.f]=1;

		}

	}

	puts("-1");

}

int main() {

	int cs=0;

	while(~scanf("%d%d%d", &n, &m, &l) && !(n==0 && m==0 && l==0)) {

		printf("Case %d: ", ++cs);



		CC(mp, 0);

		CC(vis, 0);

		q[0].f=0;

		q[0].d=0;

		ALL=(1<<((l-1)<<1))-1;



		int nx=getint(), ny=getint();

		q[0].x=nx, q[0].y=ny;

		int &f=q[0].f;

		rep(i, l-1) {

			int x=getint(), y=getint();

			if(x==nx-1) f|=(1<<(i<<1));

			else if(x==nx+1) f|=(0<<(i<<1));

			else if(y==ny-1) f|=(3<<(i<<1));

			else if(y==ny+1) f|=(2<<(i<<1));

			nx=x; ny=y;

		}

		int k=getint();

		while(k--) { int x=getint(), y=getint(); mp[x][y]=1; } 

		bfs();

	}

	return 0;

}

  

 

你可能感兴趣的:(模拟)