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