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

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;
}

  

 

posted @ 2014-09-08 20:32  iwtwiioi  阅读(387)  评论(0编辑  收藏  举报