2015 ACM/ICPC 沈阳现场赛

<题目链接>hdu


B.Bazinga

题意:

For  n  given strings  S1,S2,,Sn , labelled from  1  to  n , you should find the largest  i (1in)  such that there exists an integer  j (1j<i)  and  Sj  is not a substring of  Si .
A substring of a string  Si  is another string that occurs in  Si . For example, ``ruiz" is a substring of ``ruizhang", and ``rzhang" is not a substring of ``ruizhang".

分析:先将前n-1个串在第n个串里面的位置区间找到,然后判断两个串的时候先比较一下位置区间,假如有包含关系,就肯定一个是另一个的子串,如果不是再KMP比较一次。

代码:

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

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;

char s[502][2002];
int fail[502][2002];
int Len[502];

void getnext(int *Next,char *str,int id)  
{  
    int len=strlen(str);
    Len[id]=len;
    Next[0]=-1;  
    int k=-1;  
    int j=0;  
    while(j<len)  
    {  
        if(k==-1 ||str[j]==str[k])  
        {  
            ++j;  
 			++k;
            if(str[j]!=str[k])
            	Next[j]=k;
            else
            	Next[j]=Next[k];
        }
        else
            k=Next[k];
    }
}

int match(int id_a,int id_b,int *f)
{
	char *a=s[id_a],*b=s[id_b];
	int len1=Len[id_a],len2=Len[id_b];
	int i=0,j=0,d=len1-len2;
	while(i<len1 && d>=i-j)
	{
		if(j==-1 || a[i]==b[j])
		{
			++i;
			++j;
			if(j>=len2)
				return i-len2;
		}
		else
			j=f[j];
	}
	return -1;
}

pair <int ,int > p[20000];

int main()
{
//	freopen("da.txt","r",stdin);
//	freopen("da1.txt","w",stdout);
	int ncase,i,j,n;
	scanf("%d",&ncase);
	for(int T=1;T<=ncase;T++)
	{
		scanf("%d%*c",&n);
		for(i=1;i<=n;i++)
		{
			gets(s[i]);
			getnext(fail[i],s[i],i);
		}
		int fg=-1;
		for(i=1;i<n;i++)
		{
			int pos=match(n,i,fail[i]);
			if(pos==-1)
			{
				fg=1;
				break;
			}
			p[i]=make_pair(pos,pos+Len[i]-1);
		}
		if(fg!=-1)
		{
			printf("Case #%d: %d\n",T,n);
			continue ;	
		}
//		for(i=1;i<n;i++)
//		{
//			printf("[%d %d]\n",p[i].first,p[i].second);
//		}
		for(i=n-1;i>1 && fg==-1;i--)
		{
			for(j=1;j<i;j++)
			{
				if(!(p[i].first<=p[j].first && p[i].second>=p[j].second) && match(i,j,fail[j])==-1)
				{
					fg=i;
					break;
				}
			}
		}
		printf("Case #%d: %d\n",T,fg);	
	}
	return 0;
}


M.Meeting

题意:给你一个图G,G右很多块组成,每一块里面有Si个点,这Si个点的关系是从一个点到另一个点的时间为t。现在问两个人分别从点1和点n同时出发,最快需要多长的时间。

分析:图其实是可以存下的。。。



转化--->


这样,求出从1到每个点的最短路,再求出n到每个点的最短路,枚举位置即可。

代码:

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

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E18+9;
const int maxn = 1e6;

struct node
{
	int id;
	int w;
	int next;
}List[maxn<<3];
int head[maxn],cnt;
LL cost1[maxn],cost2[maxn],cost[maxn];
bool visit[maxn];
void Init()
{
	cnt=0;
	memset(head,-1,sizeof(head));
}
void add(int u,int v,int w) // u-->v 
{
	List[cnt].id=v;
	List[cnt].w=w;
	List[cnt].next=head[u];
	head[u]=cnt++;
}
queue <int > q;
void slack(int u,int v,LL w)
{
	if(cost[u]+w<cost[v])
	{
		cost[v]=cost[u]+w;
		if(!visit[v])
		{
			q.push(v);
			visit[v]=true;
		}
	}
}
void spfa()
{
	while(!q.empty())
	{
		int temp=q.front();
		q.pop();
		visit[temp]=false;
		int hash=head[temp];
		while(hash!=-1)
		{
			slack(temp,List[hash].id,List[hash].w);
			hash=List[hash].next;
		}
	}
}
int ans[maxn];

int main()
{
	int nCase,n,m,i,j,t,num,u;
	scanf("%d",&nCase);
	for(int T=1;T<=nCase;T++)
	{
		scanf("%d%d",&n,&m);
		int cur=1e5+6;
		Init();
		for(i=1;i<=m;i++)
		{
			scanf("%d%d",&t,&num);
			while(num--)
			{
				scanf("%d",&u);
				add(u,cur,t);
				add(cur,u,0);
			}
			cur++;
		}
		fill(cost1,cost1+maxn,INF);
		fill(cost2,cost2+maxn,INF);
		fill(cost,cost+maxn,INF);
		cost[1]=0;
		q.push(1);
		spfa();
		swap(cost,cost1);
		cost[n]=0;
		q.push(n);
		spfa();
		swap(cost,cost2);
		LL Min=INF+1,tmp;
		for(i=1;i<=n;i++)
		{
			tmp=max(cost1[i],cost2[i]);
			if(tmp<Min)
				Min=tmp;
		}
		printf("Case #%d: ",T);
		if(Min>=INF)
		{
			puts("Evil John");
			continue ;
		}
		printf("%lld\n",Min);
		int p=0;
		for(i=1;i<=n;i++)
		{
			tmp=max(cost1[i],cost2[i]);
			if(tmp==Min)
				ans[p++]=i;
		}
		printf("%d",ans[0]);
		for(i=1;i<p;i++)
		{
			printf(" %d",ans[i]);
		}
		puts("");
	}
	return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值