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

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


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

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

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

#include 
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
#include
#include
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;i0)//自动机添加一个往前走的东西。错在这里啊,好久没有用AC自动机了
            node[tmp].id=1;
        for(i=0;i0)
        {
            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



第三题:吉哥系列故事——完美队形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 
  #include 
  #include 
  #include 
  #include 
  #include 
  #include 
  #include 
  #include 
  #include 
  #include 
  #include 
  #include 
  #include 
  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
 #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]dp[j]){
                 dp[j] = dp[k] + 1;
                 f[i][j] = i*(m+1)+k;
             }
         }
     }
     int ma = 1;
     FOR(j,1,m)
         if(dp[ma]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
#include
#include
#include
#include
#include
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;ii)//i受到影响即,id+p[id]-1>=i;
        {
            p[i]=p[2*id-i];//2*id-i是i关于id的对称点相当于是id-(i-id);
            if(mx-i=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#
参数:
  
返回值:构造好的字符串长度
*/
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;ians)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 
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 maxlen)
					maxlen = len[i];
			printf("%d\n", maxlen);
		}
	}
	return 0;
}


你可能感兴趣的:(ACM,我的acm回顾)