2013金山西山居初赛第一场(hdu4545-hdu4547)

A题:用短串去长串里里面找自己(找的时候把字符转换一起考虑),找到就是happy;


代码:

#include<stdio.h>
#include<string.h>

int mat[30][30];
char s[1100],str[1200],a[3],b[3];
int main()
{
    int cas,m,i,cass;
    scanf("%d",&cass);
    for(cas=1;cas<=cass;cas++)
    {
        memset(mat,0,sizeof(mat));
        scanf("%s%s",s,str);
        scanf("%d",&m);
        for(i=0;i<26;i++) mat[i][i]=1;
        for(i=1;i<=m;i++){
            scanf("%s%s",a,b);
            mat[a[0]-'a'][b[0]-'a']=1;
        }
        for(i=m=0;str[i];i++)
        {
            if(!s[m]) break;
            if(mat[str[i]-'a'][s[m]-'a']) m++;
        }
        printf("Case #%d: ",cas);
        puts(!s[m]?"happy":"unhappy");
    }
    return 0;
}

B题:比赛的时候,没做出来,赛后在acdream群 看到[swust]MAXX大侠的解释,orz,突然醒悟,自己还是水平不够;

下面是[swust]MAXX的解释:

[swust]MAXX(405022026)  21:22:07

 B题,关键是最后的答案比较小。
比方,n>=100,光是两两配合就有10000多个了,所以答案一定是小于等于2000。
就算n比较小,答案也是15000内的
[swust]MAXX(405022026)  21:24:14
所以用dp[i]表示和值为i的组合的个数,那么就能做了

仔细想想就明白了:因为n个数最多能组合出2^n-1( C(n,0)去掉 )种,且2^14-1>10000所以最大值不会超过14个数相加的最大和也就是14000,至于当n>=100时最大值不会超过2000上面已经解释的很清楚了。

实现代码如下:

#include<stdio.h>
#include<string.h>
int dp[14100];
int Min(int a,int b){ return a<b?a:b;}
int main()
{
	int cass,cas,i,j,n,m,L,k;
	scanf("%d",&cass);
	for(cas=1;cas<=cass;cas++)
	{
		
		scanf("%d%d",&n,&m);
		if(n>100) L=2000; 
		else L=13000;
		memset(dp,0,sizeof(dp));
		for(i=1;i<=n;i++) 
		{
			scanf("%d",&k);
			for(j=L;j>=0;j--)
			{
				dp[j+k]+=dp[j];
				if(dp[j+k]>m)dp[j+k]=m+1; 
			}
			dp[k]++;
		}
		for(i=0;i<=L;i++){
			m-=dp[i];
			if(m<=0) break;
		}
		printf("Case #%d: %d\n",cas,i);
	}
	return 0;
}

C题:lca经典问题了,用rmq,tarjan算法都可以解,前者用预处理,后者可以用离线+并查集(这种方法可能麻烦点,好久没写了);

rmq版的代码:

#include<stdio.h>
#include<string.h>
#include<queue>
#include<map>
#include<string>
#include<set>
#include<algorithm>
using namespace std;

#pragma comment(linker, "/STACK:102400000,102400000")

struct E
{
	int t,next;
}edge[210000];
int ant,head[110000];

void add(int a,int b)
{
	edge[ant].t=b;
	edge[ant].next=head[a];
	head[a]=ant++;
}

map <string,int > id;
char A[100],B[100];
int p[210000],pid[110000],k,dp[210000][25];

void dfs(int root,int dep)
{
	int i;
	pid[root]=++k;
	p[k]=dep;
	for(i=head[root];i!=-1;i=edge[i].next)
	{
		dfs(edge[i].t,dep+1);
		p[++k]=dep;
	}
}
int Min(int a,int b){ return a<b?a:b;}
int lca(int l,int r)
{
	int i=0;
	if(l==r) return p[l];
	if(l>r) swap(l,r);
	while((1<<i)<(r-l+1)) i++;
	return Min(dp[l][i-1],dp[r-(1<<(i-1))+1][i-1]);
}
int vis[110000];
int main()
{
	int cas,m,i,j,n,cnt,l,r,root,t;
	scanf("%d",&cas);
	while(cas--)
	{
		ant=cnt=0;
		id.clear();
		memset(vis,0,sizeof(vis));
		memset(head,-1,sizeof(head));
		scanf("%d%d",&n,&m);
		for(i=1;i<n;i++){
			scanf("%s%s",A,B);
			if(!id[A]) id[A]=++cnt;
			if(!id[B]) id[B]=++cnt;
			add(id[B],id[A]);
			vis[id[A]]++;
		}
		for(i=1;i<=n;i++)
			if(!vis[i]) root=i;
		k=0;dfs(root,0);
		for(i=1;i<=k;i++) dp[i][0]=p[i];
		for(i=1;i<=20;i++)
			for(j=1;(j+(1<<i)-1)<=k;j++)
				dp[j][i]=Min(dp[j][i-1],dp[j+(1<<(i-1))][i-1]);
		while(m--){
			scanf("%s%s",A,B);
			l=pid[id[A]];r=pid[id[B]];t=lca(l,r);
			printf("%d\n",p[l]-t+(t!=p[r]));
		}
	}
	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值