这次的比赛。。被虐爆了。。做了一个多小时确定下来除了第一题我都做不出来之后。。。我就。。。就。。。。。
第一题:小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;
}