USACO DEC17,Platinum

        第一次打usaco,感觉题目还挺有趣的。(为啥感觉美国人的英语比日、俄的英语还要难读呢)


Standinfg Out from the Herd.

        题意:给n个字符串,对每个字符串求有多少本质不同的子串只在这个字符串中出现。

        这题我直接求了一个广义后缀自动机,然后给每个点一个标记表示这个点对应的子串是否只在某个字符串中出现。然后随便统计一下就做完了。O(N)。

AC代码如下:

#include<bits/stdc++.h>
#define N 200009
using namespace std;

int n; long long ans[N]; char s[N];
struct sam{
	int tot,fst[N],nxt[N],ch[N][26],fa[N],len[N],f[N];
	sam(){ tot=1; }
	void calc(int x,int y){ f[x]=(f[x] && f[x]!=y?-1:y); }
	int add(int k,int c,int p){
		int np=++tot; calc(np,k); len[np]=len[p]+1;
		for (; p && !ch[p][c]; p=fa[p]) ch[p][c]=np;
		if (!p){
			fa[np]=1; return np;
		}
		int q=ch[p][c];
		//cerr<<"	"<<k<<' '<<c<<' '<<p<<' '<<q<<' '<<len[p]<<' '<<len[q]<<endl;
		if (len[q]==len[p]+1) fa[np]=q; else{
			int nq=++tot; len[nq]=len[p]+1;
			//cerr<<nq<<endl;
			memcpy(ch[nq],ch[q],sizeof(ch[q]));
			fa[nq]=fa[q]; fa[q]=fa[np]=nq;
			//cerr<<q<<' '<<np<<endl;
			for (; p && ch[p][c]==q; p=fa[p]) ch[p][c]=nq;
		}
		return np;
	}
	void dfs(int x){
		int y;
		for (y=fst[x]; y; y=nxt[y]) dfs(y);
		if (f[x] && f[x]!=-1) ans[f[x]]+=len[x]-len[fa[x]];
		calc(fa[x],f[x]);
	}
	void solve(){
		int i;
		for (i=2; i<=tot; i++){
			nxt[i]=fst[fa[i]]; fst[fa[i]]=i;
		}
		dfs(1);
	}
}sam;
int main(){
	freopen("standingout.in","r",stdin); freopen("standingout.out","w",stdout);
	scanf("%d",&n);
	int i,j,len,last;
	for (i=1; i<=n; i++){
		scanf("%s",s+1);
		len=strlen(s+1);
		for (j=1,last=1; j<=len; j++) last=sam.add(i,s[j]-'a',last);
	}
	sam.solve();
	for (i=1; i<=n; i++) printf("%lld\n",ans[i]);
	return 0;
}



Push a Box

        题意:有障碍的地图上一个人推一个箱子,多次询问箱子最后能否到达目的地。

        显然要预处理全部的答案,然后每次O(1)询问。考虑用f[i][j][k]表示箱子在i,j,人在箱子的k方向上能否到达。有两种转移,分别是推一步箱子和改变人的位置。能够改变人的位置当且仅当两个点在同一个点双。

AC代码如下:

#include<bits/stdc++.h>
#define N 2009
#define M 2500009
#define E 10000009
using namespace std;

int dx[4]={-1,0,1,0},dy[4]={0,-1,0,1};
int m,n,cas,dfsclk,tot=1,cnt,tp,pt,p[N][N],px[M],py[M];
int fst[M],pnt[E],nxt[E],dfn[M],low[M],q[M],fa[M<<1];
char s[N][N]; bool ans[N][N][4],vis[N][N];
struct node{ int x,y,k; }h[M];
void add(int x,int y){
    if (!x || !y) return;
    pnt[++tot]=y; nxt[tot]=fst[x]; fst[x]=tot;
}
void dfs(int x,int p){
    int i,y; dfn[x]=low[x]=++dfsclk; q[++tp]=x;
    for (i=fst[x]; i; i=nxt[i]) if (i!=(p^1)){
        y=pnt[i];
        if (!dfn[y]){
            dfs(y,i); low[x]=min(low[x],low[y]);
	        if (low[y]==dfn[x]){
	            for (pt++; q[tp]!=y; tp--){
	                fa[q[tp]]=pt;
	            }
				fa[q[tp--]]=pt; fa[pt]=x;
	        } else if (low[y]>dfn[x]){
				while (q[tp]!=y) tp--; tp--;
			}
        } else low[x]=min(low[x],dfn[y]);
    }
}
bool check(int x,int y){
    if (!x || !y) return 0;
	//cerr<<"check: "<<x<<' '<<y<<endl;
    return fa[x] && fa[x]==fa[y] || fa[fa[x]]==y || fa[fa[y]]==x;
}
void bfs(int sx,int sy){
	int head=0,tail=1,i; node u,v;
	h[1]=(node){sx,sy,0}; vis[sx][sy]=1;
	while (head<tail){
		u=h[++head];
		for (i=0; i<4; i++){
			v=(node){u.x+dx[i],u.y+dy[i],0};
			if (s[v.x][v.y]!='B' && !vis[v.x][v.y] && p[v.x][v.y]){
				vis[v.x][v.y]=1; h[++tail]=v;
			}
		}
	}
}
int main(){
    freopen("pushabox.in","r",stdin); freopen("pushabox.out","w",stdout);
	scanf("%d%d%d",&m,&n,&cas);
    int i,j,k,x,y;
    for (i=1; i<=m; i++){
        scanf("%s",s[i]+1);
        for (j=1; j<=n; j++) if (s[i][j]!='#'){
            p[i][j]=++cnt;
            px[cnt]=i; py[cnt]=j;
        }
    }
    for (i=1; i<=cnt; i++)
        for (j=2; j<4; j++){
			add(i,p[px[i]+dx[j]][py[i]+dy[j]]);
			add(p[px[i]+dx[j]][py[i]+dy[j]],i);
		}
    pt=cnt;
    for (i=1; i<=cnt; i++) if (!dfn[i]) dfs(i,0);
	int Ax,Bx,Ay,By;
    for (i=1; i<=m; i++)
        for (j=1; j<=n; j++) if (s[i][j]=='A'){
            Ax=i; Ay=j;
        } else if (s[i][j]=='B'){
            Bx=i; By=j;
        }
	bfs(Ax,Ay);
    int head=0,tail=0;
    for (i=0; i<4; i++)
        if (vis[Bx+dx[i]][By+dy[i]]){
            h[++tail]=(node){Bx,By,i};
            ans[Bx][By][i]=1;
	//		cerr<<dx[i]<<' '<<dy[i]<<endl;
        }
	node u,v;
    while (head<tail){
        u=h[++head];
	//	cerr<<u.x<<' '<<u.y<<' '<<i<<endl;
        k=(u.k+2)&3; v=(node){u.x+dx[k],u.y+dy[k],u.k};
        if (p[v.x][v.y] && !ans[v.x][v.y][v.k]){
            ans[v.x][v.y][v.k]=1; h[++tail]=v;
        }
        k=p[u.x+dx[u.k]][u.y+dy[u.k]];
	//	cerr<<u.x+dx[u.k]<<' '<<u.y+dy[u.k]<<endl;
        for (i=0; i<4; i++)
            if (check(p[u.x+dx[i]][u.y+dy[i]],k))
                if (!ans[u.x][u.y][i]){
					//cerr<<i<<' '<<u.x+dx[i]<<' '<<u.y+dy[i]<<' '<<"gg"<<endl;
                    ans[u.x][u.y][i]=1; h[++tail]=(node){u.x,u.y,i};
                }
    }
    while (cas--){
        scanf("%d%d",&x,&y);
        puts(x==Bx && y==By || ans[x][y][0] || ans[x][y][1] || ans[x][y][2] || ans[x][y][3]?"YES":"NO");
    }
    return 0;
}


Greedy Gift Takers
        题意:有n头奶牛,每头奶牛有一个数值a[i],表示当这个奶牛在首位的时候,它会跑到倒数第a[i]+1位上。问有多少头奶牛永远不能到首位。

        首先令a[i]=n-a[i]。考虑如果a[1]=1,那么显然答案为n-1。进一步发现如果存在一个大小为M的集合{x1,...,xM},满足x1<...<xM且a[x1],...,a[xM]<=M,那么xM之后的一定不能到达首位。因此考虑二分答案,然后判断前缀中是否存在这样一个集合。如果当前不合法,就删去最大的一个,重复上述操作后如果还有点剩下来,那么剩下来的就是一个合法的集合。

AC代码如下:

#include<bits/stdc++.h>
#define N 100009
using namespace std;

int n,m,a[N];
priority_queue<int> Q;
bool check(int x){
	int i;
	while (!Q.empty()) Q.pop();
	for (i=1; i<=x; i++) Q.push(n-a[i]);
	for (; !Q.empty() && Q.top()>x; Q.pop()) x--;
	return x>0;
}
int main(){
	freopen("greedy.in","r",stdin); freopen("greedy.out","w",stdout);
	scanf("%d",&n);
	int i;
	for (i=1; i<=n; i++) scanf("%d",&a[i]);
	int l=1,r=n,mid;
	while (l<r){
		mid=l+r>>1;
		if (check(mid)) r=mid; else l=mid+1;
	}
	printf("%d\n",n-l);
	return 0;
}

by lych

2017.12.23

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值