2013腾讯编程马拉松初赛第2场(3月22)(HDU 4510 HDU4511 HDU4512 HDU4513 HDU4514)

这次的比赛。。被虐爆了。。做了一个多小时确定下来除了第一题我都做不出来之后。。。我就。。。就。。。。。


第一题:小Q系列故事——为什么时光不能倒流

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

题解:水题,格式要注意,还需要注意的是时钟。。。一圈12小时。。不是24小时。。。

#include <iostream>
using namespace std;
int main()
{
	int n;
	scanf("%d", &n);
	while (n--)
	{
		int a, b, c, d, e, f;
		scanf("%d:%d:%d %d:%d:%d", &a, &b, &c, &d, &e, &f);
		int xt = a * 3600 + b * 60 + c;
		int yt = d * 3600 + e * 60 + f;
		
		a %= 12; d%= 12;
		int xtime = a * 3600 + b * 60 + c;
		int ytime = d * 3600 + e * 60 + f;
		while (xtime < ytime) xtime += 43200;

		int cha = xtime - ytime;
		printf("%02d:%02d:%02d\n", cha/3600, (cha%3600)/60, (cha%3600)%60);
	}
	return 0;
}


第二题:小明系列故事——女友的考验

连接:http://acm.hdu.edu.cn/showproblem.php?pid=4511

题解:谁会啊。。最后了全场也就5个AC的有木有!!!

一下转自大牛(http://hi.baidu.com/chenwenwen0210/item/ca0768d039b0f1d793a974c9

解题报告:这题初看没什么头续,看到了这些路径,然后又想看的数据范围,K很好,想到了Trie,然后又想到了字符串匹配,于是想到了AC自动机。

想到了AC自动机,这题就好做了,就是一个AC自动机DP嘛。


把题目给的非法路径构成一棵Trie树,然做跑一次AC自动机。

然后做DP

dp[i][j]代表在第i个点自动机状态在j的最小距离。

然后枚举可走的点去转移就行了。

自动机状态最多有5*100个。

总的DP状态有50*500,每一个转移是50,最后的复杂度是50*50*500

刚刚过题目。

PS:一次AC,很高兴。

#include<stdio.h>
#include<math.h>
#include<string.h>
const int MAX=1005;
const int MAXSON=50;
struct
{
    int id,next[MAXSON],fail;
}node[1000000];
  
int n,tot;
char mod[1000005];
int len[MAX];
int q[1000000];
void clr()
{
    int i;
    tot++;
    for(i=0;i<MAXSON;i++)
        node[tot].next[i]=0;
    node[tot].id=node[tot].fail=0;
}
void ins()
{
    int tmp,i,n;
    int h=0;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d",&tmp);
        tmp--;
        if(node[h].next[tmp]==0)
        {
            clr();
            node[h].next[tmp]=tot;
        }
        h=node[h].next[tmp];
    }
    node[h].id++;
}
void get_fail()
{
    int h=0,i;
    int f=-1,r=0;
    int tmp,fail,k;
    q[0]=0;
    while(f!=r)
    {
        tmp=q[++f];
        if(node[node[tmp].fail].id>0)//自动机添加一个往前走的东西。错在这里啊,好久没有用AC自动机了
            node[tmp].id=1;
        for(i=0;i<MAXSON;i++)
        {
            if(node[tmp].next[i]==0)
            {
                fail=node[tmp].fail;
                node[tmp].next[i]=node[fail].next[i];
                continue;
            }
            k=node[tmp].next[i];
            fail=node[tmp].fail;
            if(node[fail].next[i]!=k)
                node[k].fail=node[fail].next[i];
            else
                node[k].fail=0;
            q[++r]=k;
        }
    }
}
const double EPS=1.0e-8;
bool dblcmp(double x)
{
    if(fabs(x)<EPS)return 0;
    return x<0?-1:1;
}
struct Point
{
    double x,y;
}p[55];
double disPP(Point a,Point b)
{
    double dx=a.x-b.x;
    double dy=a.y-b.y;
    return sqrt(dx*dx+dy*dy);
}
const double INF=1000000000.0*100000000.0;
double dp[55][5*110];
int main()
{
    int n,m;
    int i,j,k;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)break;
        for(i=1;i<=n;i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        tot=-1;
        clr();
        while(m--)
        {
            ins();
        }
        get_fail();
  
        for(i=0;i<=n;i++)
        {
            for(j=0;j<=tot;j++)
            {
                dp[i][j]=INF;
            }
        }
  
        int h=node[0].next[0];
  
        if(node[h].id>0)
        {
            puts("Can not be reached!");
            continue;
        }
  
        dp[1][h]=0;
        double cost=0;
        for(i=1;i<=n;i++)
        {
            for(j=0;j<=tot;j++)
            {
                if(dblcmp(dp[i][j]-INF)==0)continue;
                for(k=i+1;k<=n;k++)
                {
                    h=node[j].next[k-1];
                    if(node[h].id)continue;
                    cost=disPP(p[i],p[k])+dp[i][j];
                    if(cost<dp[k][h])dp[k][h]=cost;
                }
            }
        }
  
        double ans=INF;
        for(i=0;i<=tot;i++)
        {
            if(dp[n][i]<ans)ans=dp[n][i];
        }
  
        if(dblcmp(INF-ans)!=0)printf("%.2f\n",ans);
        else puts("Can not be reached!");
  
    }
    return 0;
}



第三题:吉哥系列故事——完美队形I

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

题解:(转自大牛http://www.cnblogs.com/fzf123/archive/2013/03/23/2976903.html

做法:枚举断点,分成两个段,求最长公共上升子序列。

  /*
  Author:Zhaofa Fang
  Lang:C++
  */
  #include <cstdio>
  #include <cstdlib>
  #include <sstream>
  #include <iostream>
  #include <cmath>
  #include <cstring>
  #include <algorithm>
  #include <string>
  #include <utility>
  #include <vector>
  #include <queue>
  #include <stack>
  #include <map>
  #include <set>
  using namespace std;
 
  typedef long long ll;
  #define DEBUG(x) cout<< #x << ':' << x << endl
 #define REP(i,n) for(int i=0;i < (n);i++)
 #define REPD(i,n) for(int i=(n-1);i >= 0;i--)
 #define FOR(i,s,t) for(int i = (s);i <= (t);i++)
 #define FORD(i,s,t) for(int i = (s);i >= (t);i--)
 #define PII pair<int,int>
 #define PB push_back
 #define MP make_pair
 #define ft first
 #define sd second
 #define lowbit(x) (x&(-x))
 #define INF (1<<30)
 
 int dp[205],h[205];
 int f[205][205];
 int a[205],b[205];
 int calc(int n,int m){
     memset(dp,0,sizeof(dp));
     FOR(i,1,n){
         int k = 0;
         FOR(kk,1,m)f[i][kk] = f[i-1][kk];
 
         FOR(j,1,m){
             if(b[j]<a[i] && dp[k]<dp[j])k = j;
             if(b[j]==a[i]&&dp[k]+1>dp[j]){
                 dp[j] = dp[k] + 1;
                 f[i][j] = i*(m+1)+k;
             }
         }
     }
     int ma = 1;
     FOR(j,1,m)
         if(dp[ma]<dp[j])ma = j;
     return dp[ma];
 }
  int main()
 {
      //freopen("in","r",stdin);
      int T;
      scanf("%d",&T);
      while(T--){
         int n;
         scanf("%d",&n);
         FOR(i,1,n)scanf("%d",&h[i]);
         int ans = -1;
         FOR(i,1,n){
             int tmp1,tmp2;
             FOR(j,1,i)a[j] = h[j];
             FORD(j,n,i+1)b[n+1-j] = h[j];
             tmp1 = calc(i,n-i);
 
             b[n-i+1] = h[i];
             tmp2 = calc(i,n-i+1);
             if(tmp2>tmp1)ans = max(ans,tmp1*2+1);
             else ans = max(ans,tmp1*2);
         }
         printf("%d\n",ans);
      }
      return 0;
  }



第四题:吉哥系列故事——完美队形II

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

题解:(转自:http://hi.baidu.com/chenwenwen0210/item/51b72039793833f56d15e9ba

解题报告:这题其实是求一个最长的回文子串,这儿和以前不一样的是要求是先上升后下降。

我们可以通过Manacher算法改造过来

下面是学习资料。

http://hi.baidu.com/chenwenwen0210/item/482c84396476f0e02f8ec230


和普通回文串不一样的地方就是每一扩展的时候要判断一下是不是<=前面的值。

具体改造见代码。

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<map>
#include<algorithm>
#include<queue>
using namespace std;
typedef __int64 lld;
  
const int MAX=110000*2;
int str[MAX];//原字符串
int sb[MAX];
int p[MAX];//表示以i为中心的回文半径,
/*p[i]-1刚好是原字符串以第i个为中心的回文串长度。
画画图就知道了,因为两端配匹的肯定是字符g
*/
/*
Mancher主算法。
学习地址:http://blog.csdn.net/ggggiqnypgjg/article/details/6645824
功能:求出以i为中心的回文半径p[i];
参数:传入构造好的字符串长度
特殊说明:因为前面加了一个无效字符,所以下标从1开始。
例题:http://acm.hdu.edu.cn/showproblem.php?pid=3068
http://poj.org/problem?id=3974
http://acmpj.zstu.edu.cn/JudgeOnline/showproblem?problem_id=3780
http://acmpj.zstu.edu.cn/JudgeOnline/showproblem?problem_id=3769
http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=12581#problem/A
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3661
http://acm.hdu.edu.cn/showproblem.php?pid=3948
  
*/
bool dig(char x){return x>='0'&&x<='9';}
int getval()
{
    int ret=0,sign=1;
    char c;
    while(!dig(c=getchar())&&c!='-');
    if(c=='-')sign=-1;
    else ret=c-'0';
    while(dig(c=getchar()))ret=ret*10+c-'0';
    return ret*sign;
}
void Manacher(int n)
{
    int i;
    int mx=0;//记录前面回文串最长影响到的地方。不一定是最长回文串造成的。
    int id;//最长影响串的ID;
    p[0]=0;
    for(i=1;i<n;i++)
    {
        p[i]=1;//至少是1
        if(mx>i)//i受到影响即,id+p[id]-1>=i;
        {
            p[i]=p[2*id-i];//2*id-i是i关于id的对称点相当于是id-(i-id);
            if(mx-i<p[i])p[i]=mx-i;
            //由于对称点的回文半径可能超过mx-i,因为mx后面的还没有配过
            //所以要取小的。等等继续配
        }
  
        //向两端配匹
        while(str[i-p[i]]==str[i+p[i]])
        {
            if(str[i+p[i]]==1)
            {
                p[i]++;
            }
            else
            {
                int a=i-p[i];
                int b=i+p[i];
  
                if(a+2<=b-2&&str[a]<=str[a+2]&&str[b-2]>=str[b])
                {
                    p[i]++;
                    continue;
                }
                else if(a==b)
                {
                    p[i]++;
                    continue;
                }
                else if(a+2>b-2)
                {
                    p[i]++;
                    continue;
                }
              
  
                break;
            }
        }
  
        if(i+p[i]>mx)
        {
            mx=i+p[i];
            id=i;
        }
    }
}
  
/*
功能:构造字符串,在每一个字符前插入一个,g,一般用'#'
第一个字符前面再插入,first,一般用'$'
最后再插入g字符
总之不是在输入中出现的字符就行了。
比如abb,构造成$#a#b#b#
参数:<first,第一个字符>,<g,一般字符>
  
返回值:构造好的字符串长度
*/
int pre(int first,int g,int m)
{
    int i,n=0;
    memcpy(sb,str,sizeof(int)*(m+2));
    str[0]=first;
    n++;
    for(i=0;i<m;i++)
    {
        str[n++]=g;
        str[n++]=sb[i];
    }
  
    str[n++]=g;
    str[n]=3;
    return n;
}
int main()
{
    int n;
    int i;
    int CS=1;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            //scanf("%d",&str[i]);
            str[i]=getval();
        }
        n=pre(0,1,n);
        Manacher(n);
        int ans=0;
  
        for(i=1;i<n;i++)
        {
            if(p[i]>ans)ans=p[i];
        }
  
        printf("%d\n",ans-1);
    }
    return 0;
}
另一位大牛的: http://www.cnblogs.com/aigoruan/archive/2013/03/22/2976538.html

代码就不贴了。。。


第五题:湫湫系列故事——设计风景线

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

题解:好久没做图论了。。这次看到傻眼了。。。于是当时就没做。。第二天起床之后发现原来没那么难。。。。简单一个并查集就行了。。我狂晕。。。最好一次机会让我给错过了。。以后比赛坚决不能放弃了。。。。。

#include <iostream>
using namespace std;
#define min(a,b)	((a)<(b)?(a):(b))
#define max(a,b)	((a)>(b)?(a):(b))
const int maxn = 1000005;

int fa[maxn], len[maxn];
int n, m;

int find(int x)
{
	if (x == fa[x]) return x;
	return find(fa[x]);
}

int main()
{
	while (scanf("%d %d", &n, &m) != EOF)
	{
		int i;
		bool flag = false;
		for (i=0; i <= n; i++)	fa[i] = i;
		memset(len, 0, (n+1)*sizeof(len[0]));

		for (i=0; i<m; i++)
		{
			int a, b, length;
			scanf("%d %d %d", &a, &b, &length);
			int faa = find(a);
			int fab = find(b);
			if (faa == fab) flag = true;
			else if (!flag)	//剪枝
			{
				int c = min(faa,fab);
				int d = max(faa,fab);
				fa[d] = c;
				len[c] += length;
			}
		}
		if (flag)
			puts("YES");
		else
		{
			int maxlen = 0;
			for (i=1; i<=n; i++)
				if (len[i] > maxlen)
					maxlen = len[i];
			printf("%d\n", maxlen);
		}
	}
	return 0;
}


  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值