今天上午没事做了下昨天腾讯的比赛,发现竟然全部都会,早知道就选昨天的比赛就好了,废话不多说,下面是我的一些想法和代码。
http://acm.hdu.edu.cn/showproblem.php?pid=4520
hdu 4520:
小Q系列故事——最佳裁判
过去的2012年对小Q来说是很悲催的一年,失恋了12次,每次都要郁闷1个来月。好在小Q是个体育迷,在最痛苦的时候,他常常用观看各种体育节目来麻醉自己,比如伦敦奥运会期间,小Q就常常在周末邀上一群单身同事聚在自己的蜗居,一边畅饮啤酒,一边吹牛。
小Q最喜欢看的是跳水,主要原因也是因为这个项目有中国人参加,而且中国队员获胜的几率很大,一般不会再给自己添堵,不然何谈看体育疗情伤呢。
跳水项目的一个重要环节就是裁判打分,小Q他们有时候会觉得某个裁判不公平,是不是有意在压中国队员的分数。于是每当一个队员跳水完毕,他们几个也像电视上的裁判那样给队员打分,并且规定,谁的分数和最终得分最接近谁就是他们当中的最佳裁判,现场奖励啤酒一杯!
其中,最终得分是这样计算的:N个人打分,去掉一个最高分,去掉一个最低分,然后剩余分数相加,再除以N-2即为最终得分。
凭借“看体育疗情伤”而练就的专业体育知识,小Q几乎每局必胜,这一夜,小Q注定要烂醉如泥了......
思路:很水的题,把最终得分求出来然后一个一个比较即可。
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <stdio.h>
using namespace std;
double a[110];
double max(double a,double b)
{
return a>b?a:b;
}
double min(double a,double b)
{
return a<b?a:b;
}
int main()
{
freopen("dd.txt","r",stdin);
int n;
while(scanf("%d",&n)&&n)
{
int i,ans;
double ma=0,mi=20,sum=0;
for(i=1;i<=n;i++)
{
scanf("%lf",&a[i]);
sum+=a[i];
ma=max(ma,a[i]);
mi=min(mi,a[i]);
}
sum-=mi+ma;
sum/=(n-2);
double tmp=20;
for(i=1;i<=n;i++)
{
if(fabs(sum-a[i])<tmp)
{
ans=i;
tmp=fabs(sum-a[i]);
}
}
printf("%d\n",ans);
}
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=4521
hdu 4521:
小明系列问题——小明序列
大家都知道小明最喜欢研究跟序列有关的问题了,可是也就因为这样,小明几乎已经玩遍各种序列问题了。可怜的小明苦苦地在各大网站上寻找着新的序列问题,可是找来找去都是自己早已研究过的序列。小明想既然找不到,那就自己来发明一个新的序列问题吧!小明想啊想,终于想出了一个新的序列问题,他欣喜若狂,因为是自己想出来的,于是将其新序列问题命名为“小明序列”。提起小明序列,他给出的定义是这样的:
①首先定义S为一个有序序列,S={ A1 , A2 , A3 , ... , An },n为元素个数 ;
②然后定义Sub为S中取出的一个子序列,Sub={ Ai1 , Ai2 , Ai3 , ... , Aim },m为元素个数 ;
③其中Sub满足 Ai1 < Ai2 < Ai3 < ... < Aij-1 < Aij < Aij+1 < ... < Aim ;
④同时Sub满足对于任意相连的两个Aij-1与Aij都有 ij - ij-1 > d (1 < j <= m, d为给定的整数);
⑤显然满足这样的Sub子序列会有许许多多,而在取出的这些子序列Sub中,元素个数最多的称为“小明序列”(即m最大的一个Sub子序列)。
例如:序列S={2,1,3,4} ,其中d=1;
可得“小明序列”的m=2。即Sub={2,3}或者{2,4}或者{1,4}都是“小明序列”。
当小明发明了“小明序列”那一刻,情绪非常激动,以至于头脑凌乱,于是他想请你来帮他算算在给定的S序列以及整数d的情况下,“小明序列”中的元素需要多少个呢?
思路:数据结构题,我用线段树过的,我们设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
hdu 4522:
湫湫系列故事——过年回家
出门在外,最想念的还是家,对在深圳腾讯工作的HR湫湫来说,春节回家是一年中最期盼的事,不仅可以见到阔别已久的亲人,还能以相亲的名义调侃众多帅哥(她的内心告诉她:如果相亲能遇到参加过腾讯编程马拉松的同学,就直接把自己嫁了~)。
同时,每年的春节湫秋也都会纠结一把,因为车票实在是太难抢了,不过2013的春节有点特殊,作为一个曾经的ACMer,湫湫制作出了很完美的刷票机,也就是说她再也不用担心买不上票了,但是想来想去还是觉得随便买票实在是浪费了辛辛苦苦搞出来的刷票机,所以她决定要用最舒适的方式回家。
假设湫湫有可能经过的n个城市分别编号从1到n,湫湫要从城市A回到城市B,购票网站上列出了t辆列车行程,每辆车的行程用一个字符串表示,途径的城市间用+号相连,如1+2+3+5代表一辆从1城市分别经过2,3到达5的火车,湫湫可以从中间任意一站出发和下车(路径是单向的,即必须沿字符串从左到右来走),每个字符串对应着一个整数k,k=0表示该车只有硬座,k=1表示该车有卧铺也有硬座,在整个回家的计划中,同一辆车可以坐无限次,为了中途换车的方便,如果在起点坐的是卧铺,则后面乘坐的车必须全是卧铺,同样的,如果在起点坐的是硬座,则后面乘坐的车必须全是硬座,假设一段(一辆车行程中,两相邻城市间为一段)硬座的不舒适度是D1,一段卧铺的不舒适度是D2,求湫湫回家最小的不舒适度。
同时,每年的春节湫秋也都会纠结一把,因为车票实在是太难抢了,不过2013的春节有点特殊,作为一个曾经的ACMer,湫湫制作出了很完美的刷票机,也就是说她再也不用担心买不上票了,但是想来想去还是觉得随便买票实在是浪费了辛辛苦苦搞出来的刷票机,所以她决定要用最舒适的方式回家。
假设湫湫有可能经过的n个城市分别编号从1到n,湫湫要从城市A回到城市B,购票网站上列出了t辆列车行程,每辆车的行程用一个字符串表示,途径的城市间用+号相连,如1+2+3+5代表一辆从1城市分别经过2,3到达5的火车,湫湫可以从中间任意一站出发和下车(路径是单向的,即必须沿字符串从左到右来走),每个字符串对应着一个整数k,k=0表示该车只有硬座,k=1表示该车有卧铺也有硬座,在整个回家的计划中,同一辆车可以坐无限次,为了中途换车的方便,如果在起点坐的是卧铺,则后面乘坐的车必须全是卧铺,同样的,如果在起点坐的是硬座,则后面乘坐的车必须全是硬座,假设一段(一辆车行程中,两相邻城市间为一段)硬座的不舒适度是D1,一段卧铺的不舒适度是D2,求湫湫回家最小的不舒适度。
思路:裸的最短路问题,建两个图一个是卧铺的,一个是硬座的,求最短路后,如果两边均不可达,则输出-1,否则输出两者的最小值即可。代码如下:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <queue>
#include <algorithm>
#define maxn 100010
using namespace std;
struct edge
{
int to;
int next;
}e[2][maxn<<1];
int box[2][210],cnt[2],dist[2][210],c[2][210],inf;
void init()
{
memset(box,-1,sizeof(box));
memset(dist,1,sizeof(dist));
memset(c,0,sizeof(dist));
inf=dist[0][0];
cnt[0]=cnt[1]=0;
}
void add(int from,int to,int t)
{
e[t][cnt[t]].to=to;
e[t][cnt[t]].next=box[t][from];
box[t][from]=cnt[t]++;
}
char str[10010];
void makemap(int t)
{
int len=strlen(str),i;
str[len]='+';
str[++len]='\0';
int from=0,to=0,tmp=0;
for(i=0;i<len;i++)
{
if(str[i]=='+')
{
if(from!=0)
{
if(t)
add(from,tmp,1);
add(from,tmp,0);
}
from=tmp;
tmp=0;
}
else
tmp=10*tmp+str[i]-'0';
}
}
void spfa(int s,int tt)
{
queue<int> q;
dist[tt][s]=0;
c[tt][s]=1;
q.push(s);
while(!q.empty())
{
int now=q.front();
q.pop();
c[tt][now]=0;
int t,v;
for(t=box[tt][now];t+1;t=e[tt][t].next)
{
v=e[tt][t].to;
if(dist[tt][v]>dist[tt][now]+1)
{
dist[tt][v]=dist[tt][now]+1;
if(!c[tt][v])
{
c[tt][v]=1;
q.push(v);
}
}
}
}
}
long long min(long long a,long long b)
{
return a<b?a:b;
}
int main()
{
//freopen("dd.txt","r",stdin);
int ncase;
scanf("%d",&ncase);
while(ncase--)
{
int n,t,flag;
init();
scanf("%d%d",&n,&t);
while(t--)
{
scanf("%s%d",str,&flag);
makemap(flag);
}
int c1,c2;
scanf("%d%d",&c1,&c2);
int S,T;
scanf("%d%d",&S,&T);
spfa(S,0);
spfa(S,1);
long long t1=dist[0][T],t2=dist[1][T];
if(t1==inf&&t2==inf)
printf("-1\n");
else
{
printf("%I64d\n",min(c1*t1,c2*t2));
}
}
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=4523
hdu 4523:
威威猫系列故事——过生日
2月29号是威威猫的生日,由于这个日子非常特殊,4年才一次,所以生日这天许多朋友都前往威威猫家祝贺他的生日。
大家给威威猫买了一个非常大非常大的蛋糕,蛋糕的形状是一个有n条边的凸多边形,可是威威猫的审美观有一点奇怪,他只喜欢有m条边的蛋糕,所以他要伙伴们把这个蛋糕切p次,然后给他一个只有m条边的新蛋糕。这下大家急了,这不是坑爹吗,审美观崎岖作怪。
假设蛋糕可看成一个平面含n条边的凸多边形,每一刀必须沿直线切下去,p刀之后能给威威猫切出一个m条边的蛋糕吗?
大家给威威猫买了一个非常大非常大的蛋糕,蛋糕的形状是一个有n条边的凸多边形,可是威威猫的审美观有一点奇怪,他只喜欢有m条边的蛋糕,所以他要伙伴们把这个蛋糕切p次,然后给他一个只有m条边的新蛋糕。这下大家急了,这不是坑爹吗,审美观崎岖作怪。
假设蛋糕可看成一个平面含n条边的凸多边形,每一刀必须沿直线切下去,p刀之后能给威威猫切出一个m条边的蛋糕吗?
思路:很水的一题,若n+p<m或m<3或p==0且n!=m输出NO,否则输出YES。关键还是数据范围太大,要用高精度。
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
#define MAX 1000
#define mod 10
#define baselen 1
struct bint
{
int dig[MAX];
int len;
};
typedef struct bint hp;
void add1(hp a,hp b,hp *c)//高精度加高精度
{
int i,carry;
for(i=carry=0;i<=a.len||i<=b.len||carry;i++)
{
if(i<=a.len)
carry+=a.dig[i];
if(i<=b.len)
carry+=b.dig[i];
c->dig[i]=carry%mod;
carry/=mod;
}
c->len=i-1;
}
int cmp(hp a,hp b)//比较a与b的大小 若a>b 返回正数 若相等 返回0 a<b 则返回负数
{
if(a.len<b.len)
return -1;
if(a.len>b.len)
return 1;
int i=a.len;
while(i&&a.dig[i]==b.dig[i])
i--;
return a.dig[i]-b.dig[i];
}
int input(hp *a,char *data)//输入高精度正整数
{
int i,j,k,len,p;
len=strlen(data)-1;
a->len=0;
for(p=0;p<=len&&data[p]=='0';p++);
while(1)
{
i=j=0,k=1;
while(i<baselen&&len>=p)
{
j=j+(data[len--]-'0')*k;
k*=10;
i++;
}
a->dig[a->len++]=j;
if(len<p)
break;
}
a->len--;
return 1;
}
hp n,m,p;
char a[110],b[110],c[110];
int main()
{
//freopen("dd.txt","r",stdin);
while(scanf("%s%s%s",a,b,c)!=EOF)
{
input(&n,a);
input(&m,b);
input(&p,c);
add1(n,p,&n);
int tmp=cmp(n,m);
if(tmp<0)
printf("NO\n");
else if(p.len==0&&p.dig[0]==0&&tmp!=0)
printf("NO\n");
else
{
if(m.len==0&&m.dig[0]<3)
printf("NO\n");
else
printf("YES\n");
}
}
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=4524
hdu 4524:
郑厂长系列故事——逃离迷宫
郑厂长没变
还是那个假厂长真码农
改变的是业余爱好
他现在不研究象棋,改玩游戏了!
最近,郑厂长爱上了逃离迷宫这个游戏,他日日夜夜的玩,就是想达到自己的目标:1000万,因为这个数字和他在腾讯的年收入一样多。
不过,在他跑到9999999时,游戏屏幕上突然出现了好多箱子,郑厂长必须要消除所有这些箱子才能继续玩游戏。这些箱子排成一行,每个箱子上都有个数字,每个数字代表这个箱子需要被点击的次数才会消失。每个箱子被点击时对应数字会减1,并且他右边箱子的数字也会同时减1,当箱子数字变成0,则其就就消失了。需要说明的是,如果右边没有箱子或者右边的箱子已经消失了,则无法操作当前的箱子(以上所说的“右边”只是指紧挨着的右边,隔开的不算)。
现在已知这些箱子的信息,请问郑厂长是否能成功消除所有的箱子然后继续达成他的千万梦想呢?
还是那个假厂长真码农
改变的是业余爱好
他现在不研究象棋,改玩游戏了!
最近,郑厂长爱上了逃离迷宫这个游戏,他日日夜夜的玩,就是想达到自己的目标:1000万,因为这个数字和他在腾讯的年收入一样多。
不过,在他跑到9999999时,游戏屏幕上突然出现了好多箱子,郑厂长必须要消除所有这些箱子才能继续玩游戏。这些箱子排成一行,每个箱子上都有个数字,每个数字代表这个箱子需要被点击的次数才会消失。每个箱子被点击时对应数字会减1,并且他右边箱子的数字也会同时减1,当箱子数字变成0,则其就就消失了。需要说明的是,如果右边没有箱子或者右边的箱子已经消失了,则无法操作当前的箱子(以上所说的“右边”只是指紧挨着的右边,隔开的不算)。
现在已知这些箱子的信息,请问郑厂长是否能成功消除所有的箱子然后继续达成他的千万梦想呢?
思路:水题,从左到右遍历一遍,若出现a[i]>a[i+1]则无解,否则,从左到右依次使a[i]-=a[i-1],做到最后,若a[n]不为0,则无解,否则有解。代码如下:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#define maxn 1000010
using namespace std;
int a[maxn];
int min(int a,int b)
{
return a<b?a:b;
}
int main()
{
freopen("dd.txt","r",stdin);
int ncase,n,i;
scanf("%d",&ncase);
while(ncase--)
{
scanf("%d",&n);
int tru=1;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(i=1;i<n;i++)
{
if(a[i]>a[i+1])
{
tru=0;
break;
}
else
{
a[i+1]-=a[i];
}
}
if(!tru||a[n])
printf("I will never go out T_T\n");
else
printf("yeah~ I escaped ^_^\n");
}
return 0;
}