2013腾讯编程马拉松初赛第4场(3月24)(HDU 4520 HDU4521 HDU4522 HDU4523 HDU4524)

    话说昨天比赛终于拿到一个不错的名次,rank77,对于我们这种ACM弱菜的学校来说已经很好了,可惜我1003用了俩floyd超时,如果我最近稍微搞搞图论的话,用个bellman,或者SPFA,绝对超不了了就。。。哎。。他们的1002貌似也差点出来。。。还有1004被坑人的wa了两次。。。。

    理工大的孩子们看到之后,一定好好整理下,不管是这场比赛,还是前几场,比完之后整理再做这些题比较重要。这次比赛的题都不是出不来的,大家加油了。。。


第一题:小Q系列故事——最佳裁判

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4520

题解:水题啊。。懒得看。。贴大牛毕鲁阳的代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

struct cp
{
    int num;
    double p;
} P[22];
int cmp(cp a, cp b)
{
    return a.p > b.p ? 1 : 0;
}
int main()
{
    int n;
    double sum = 0 ;
    double ave;
    int ans;
    double m;
    while(scanf("%d",&n),n)
    {
        sum = 0;
        m = 999999999;
        for(int i = 0; i < n; i++)
        {
            scanf("%lf",&P[i].p);
            P[i].num = i+1;
        }
        sort(P,    P+n,cmp);
        for(int i = 1; i < n-1; i++)
        {
            sum += P[i].p;
        }
        ave = sum / (n-2);
        for(int i = 0; i <n; i++)
        {
            if(abs(P[i].p-ave)<m)
            {
                m = abs(P[i].p-ave);
                ans = P[i].num;
            }
        }
        printf("%d\n",ans);
        
    }
    return 0;
}





第二题:小明系列问题——小明序列

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4521

题解:(转自大牛:http://blog.csdn.net/dyx404514/article/details/8716229)

思路:数据结构题,我用线段树过的,我们设dp[i]为以Ai结尾满足小明序列要求的最长子序列的长度,我们可用线段树来维护这n个位置。但是只用线段树还不够,我们首先将Ai排一个序,先按Ai的大小从小到大排列,若数字相等则按位置从大到小排列。这样我们按排列后的序列依次求dp[i],然后更新线段树中对应的值。具体做法是:我们设当前我们要求的数字的位置是po,则我们只要在线段树中求区间[1,po-d-1]的最大值再加上1即为所求,为什么呢,因为经过排序后,我们在求位置dp[po]时,我们可以保证前面所求的数要么数字比当前求的小,要么位置在po之后(从而不影响dp[po]的值),所以这样做是对的。求完之后不要忘了更新线段树,将第po个数赋值为dp[po]。代码如下:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#define maxn 100010
#define mid ((t[p].l+t[p].r)>>1)
#define ls (p<<1)
#define rs (ls|1)
using namespace std;
struct tree
{
    int l,r;
    int max;
}t[maxn<<2];
int max(int a,int b)
{
    return a>b?a:b;
}
void pushup(int p)
{
    t[p].max=max(t[ls].max,t[rs].max);
}
void build(int p,int l,int r)
{
    t[p].l=l,t[p].r=r;
    if(l==r)
    {
        t[p].max=0;
        return;
    }
    build(ls,l,mid);
    build(rs,mid+1,r);
    pushup(p);
}
void change(int p,int x,int val)
{
    if(t[p].l==t[p].r)
    {
        t[p].max=val;
        return;
    }
    if(x>mid)
    change(rs,x,val);
    else
    change(ls,x,val);
    pushup(p);
}
int query(int p,int l,int r)
{
    if(l>r)
    return 0;
    if(t[p].l==l&&t[p].r==r)
    {
        return t[p].max;
    }
    if(l>mid)
    return query(rs,l,r);
    else if(r<=mid)
    return query(ls,l,r);
    else
    return max(query(ls,l,mid),query(rs,mid+1,r));
}
struct node
{
    int po;
    int num;
}a[maxn];
bool cmp(node a,node b)
{
    if(a.num==b.num)
    return a.po>b.po;
    return a.num<b.num;
}
int main()
{
   // freopen("dd.txt","r",stdin);
    int n,d;
    while(scanf("%d%d",&n,&d)!=EOF)
    {
        int i;
        build(1,1,n);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i].num);
            a[i].po=i;
        }
        sort(a+1,a+n+1,cmp);
        int ans=0;
        for(i=1;i<=n;i++)
        {
            int po=a[i].po,tmp=query(1,1,po-d-1);
            ans=max(ans,tmp+1);
            change(1,po,tmp+1);
        }
        printf("%d\n",ans);
    }
    return 0;
}





第三题:湫湫系列故事——过年回家

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4522

题解:纯最短路,我以为数据量200就可以用floyd了。。结果题目要求0.2s。。超时好几次啊。。好久没弄图论了,都不会了我晕。。。第二天敲来敲去,被一个小错误卡住了。。。

#include <iostream>
#include <string>
using namespace std;
#define min(x,y)	((x)<(y)?(x):(y))
#define inf	(0x3f7f7f7f)
const int maxn = 207;

int map[2][maxn][maxn], cost[2][maxn];
bool vis[maxn];
//map[0]卧铺  map[1]硬座
int n, t, d1, d2, a, b;

void dijk(int flag)
{
	int i, j;
	memset(vis, false, sizeof(vis));
	vis[a] = true;
	for (i=1; i<=n; i++)
		cost[flag][i] = map[flag][a][i];

	for (i=1; i<n; i++)
	{
		int min = inf, imin = a;
		for (j=1; j<=n; j++)
			if (!vis[j] && cost[flag][j] < min)
			{
				min = cost[flag][j];
				imin = j;
			}
		if (min == inf) return ;
		vis[imin] = true;

		for (j=1; j<=n; j++)
		{
			if (!vis[j] && cost[flag][imin] + map[flag][imin][j] < cost[flag][j] && map[flag][imin][j] < inf)
				cost[flag][j] = cost[flag][imin] + map[flag][imin][j];
		}
	}
}

int main()
{
	int q;
	scanf("%d", &q);
	while (q--)
	{
		memset(map, inf, sizeof(map));
		scanf("%d %d", &n, &t);
		int i, flag;
		for (i=0; i<t; i++)
		{
			int tmp[5000], j=0;
//			memset(tmp, 0, sizeof(tmp));
			char c = '+';
			while (c == '+')
			{
				scanf("%d", &tmp[j++]);
				c = getchar();
			}
			scanf("%d", &flag);

			int k;
			if (flag) //有卧铺和硬座
				for (k=1; k<j; k++)
				{
					map[0][tmp[k-1]][tmp[k]] = 1;
					map[1][tmp[k-1]][tmp[k]] = 1;
				}
			else	//硬座
				for (k=1; k<j; k++)
				{
					map[1][tmp[k-1]][tmp[k]] = 1;
				}
		}

		for (i=0; i<=n; i++) map[0][i][i] = map[1][i][i] = 0;
		scanf("%d %d", &d1, &d2);
		scanf("%d %d", &a, &b);

		dijk(0); dijk(1);

		//本来少了俩elseif。。就是过不了。。。最后发现。。cost[0][b]*d2 和 cost[1][b]*d1 都可能越界我晕!
		if (cost[0][b] >= inf && cost[1][b] >= inf)
			puts("-1");
		else if (cost[0][b] >= inf)
			printf("%d\n", cost[1][b]*d1);
		else if (cost[1][b] >= inf)
			printf("%d\n", cost[0][b]*d2);
		else
			printf("%d\n", min(cost[0][b]*d2, cost[1][b]*d1));
	}
	return 0;
}




第四题:威威猫系列故事——过生日

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4523

题解:两个地方要注意,第一就是我一开始没看到数据量wa了一次。。。10^100 我还用int。。真惊了。。当时只图快了。。结果这下就是20分钟。。哎。。。第二点要注意就是。。杭电相当坑人的M。。他的范围是 M>0 的!!!这就意味着当M为1或者2的时候。。。n和p无论是多少都分割不出来1边形和2边形。。。。又WA一次。。。哎。。欲速则不达啊!!一共罚了40分钟。。。

import java.math.BigInteger;
import java.util.Scanner;

public class main {

	public static void main(String[] args) {
		BigInteger n, m, p;

		Scanner cin = new Scanner(System.in);
		while (cin.hasNextBigInteger())
		{
			 n = cin.nextBigInteger();
	         m = cin.nextBigInteger();
	         p = cin.nextBigInteger();
	         BigInteger tmp1 = n.add(p);
	         BigInteger tmp2 = BigInteger.valueOf(3);
	         if (tmp1.compareTo(m) < 0 || m.compareTo(tmp2) < 0)
	        	 System.out.println("NO");
	         else
	        	 System.out.println("YES");
		}
	}
}



第五题:郑厂长系列故事——逃离迷宫

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4524

题解:一开始没看懂题意,好郁闷,我理解能力的确有点问题,题目的意思,右边倒数第一个格子和倒数第二个格子必须同时消失,否则郑厂长就无法进行操作。。。就是这里有点坑。。其他都没什么难的。。

#include <iostream>
using namespace std;
int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
	{
		int n;
		scanf("%d", &n);
		bool flag = true;
		int i, tmp, num=0;
		for (i=0; i<n; i++)
		{
			scanf("%d", &tmp);
			if (i==n-1 && tmp != num) flag = false;
			if (tmp < num) flag = false;
			else num = tmp - num;
		}
		if (flag)
			puts("yeah~ I escaped ^_^");
		else
			puts("I will never go out T_T");
	}
	return 0;
}




你可能感兴趣的:(hdu4522,腾讯编程马拉松,hdu4521,hdu4523,hdu4524)