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