zoukankan      html  css  js  c++  java
  • 中秋节模拟赛之冷月葬花魂(被虐瞎)

    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]=''; 
    		int an=d[id[now]];
    		printf("%s ", pr);
    		if(an || !strcmp(pr, "Xiaodao")) printf("%d
    ", 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
    ", 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] << '	'; 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
    ", 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] << '	'; 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
    ", 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;
    }
    

      

  • 相关阅读:
    递归-计算排列组合问题
    递归-字符串翻转
    递归-求字符串的子序列
    递归
    递归
    PHP开发工程师-技能树
    Graph-BFS-Fly-图的广度优先遍历-最小转机问题
    Graph-DFS-Map-图的深度优先遍历-城市地图问题
    Graph-BFS-图的广度优先遍历
    Graph-DFS-图的深度优先遍历
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/3961673.html
Copyright © 2011-2022 走看看