比赛地址:http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=17898#overview
第1题;判断四个长度不一的边能否构成三角形。。。
分析:纯粹判断题,排序后更简单。。。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a[4],c;
int solve()
{
if(a[0]+a[1]>a[2])return 1;
if(a[1]+a[2]>a[3])return 1;
if(a[0]+a[1]==a[2])return 2;
if(a[1]+a[2]==a[3])return 2;
return 0;
}
int main()
{
while(~scanf("%d%d%d%d",&a[0],&a[1],&a[2],&a[3]))
{
sort(a,a+4);
c=solve();
if(c==0)puts("IMPOSSIBLE");
if(c==1)puts("TRIANGLE");
if(c==2)puts("SEGMENT");
}
return 0;
}
第2题:给你一张n*m的地图,地图上有一些大写字母,每一个字母代表一个人,问与给定字母相邻的人有几个?
分析:直接枚举相邻的两个字母,判断其中是否有给定的字母,有的话就标记两个人。。。注意边界,我偷懒导致wa了
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int mm=111;
char map[mm][mm],ps;
int p[333];
int i,j,n,m,ans;
int main()
{
while(~scanf("%d%d %c",&n,&m,&ps))
{
for(i=0;i<n;++i)
scanf("%s",map[i]);
memset(p,0,sizeof(p));
p[ps]=1;
for(i=0;i<n;++i)
for(j=0;j<m;++j)
{
if(map[i][j]==ps)
{
if(j)p[map[i][j-1]]=1;
if(i)p[map[i-1][j]]=1;
}
if(i&&map[i-1][j]==ps)p[map[i][j]]=1;
if(j&&map[i][j-1]==ps)p[map[i][j]]=1;
}
ans=-1;
for(i='A';i<='Z';++i)ans+=p[i];
printf("%d\n",ans);
}
return 0;
}
第3题:给你n块巧克力,吃完每块需要的时间,问两个人从两边开始吃,最后他们都吃了几块,同时吃的情况,让给左边的女生
分析:直接开两个指针,还有统计两个人所花的时间,直接模拟即可。。。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int mm=111111;
int t[mm];
int i,j,n,ta,tb;
int main()
{
while(~scanf("%d",&n))
{
for(i=1;i<=n;++i)
scanf("%d",&t[i]);
ta=tb=0;
i=1,j=n;
while(i<=j)
{
if(ta<=tb)ta+=t[i++];
else tb+=t[j--];
}
printf("%d %d\n",i-1,n-i+1);
}
return 0;
}
第4题:给你n个人,每次你可以打中2~n-1中的任何一个,与他相邻的也会受到b的伤害,死后也可以继续打,太凶残了= =
分析:数据较小,所以我立马想到可以用搜索搞,考虑按顺序来搞,第一个人只能通过第二个位置来搞定,所以第二个位置至少要放置的火球数已知,考虑普通情况下,前一个人还没死,那么至少需要的火球数也可以计算,所以可以枚举每一个位置的火球数来模拟计算,加个最优化剪枝直接搞定。。。当然也有DP的解法。。。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int h[22],t[22],s[22],out[22];
int i,a,b,n,ans;
int count(int s,int a)
{
int ret=0;
while(s>=0)s-=a,++ret;
return ret;
}
void dfs(int l,int sum)
{
if(sum>=ans)return;
int i,tmp;
if(l==n)
{
tmp=max(count(h[n]-s[n],b),count(h[n-1]-s[n-1],a));
if(ans>sum+tmp)
{
ans=sum+tmp;
for(i=2;i<n;++i)out[i]=t[i];
out[n-1]+=tmp;
}
return;
}
tmp=count(h[l-1]-s[l-1],b);
if(tmp+sum>=ans)return;
s[l-1]+=b*(tmp-1),s[l]+=a*(tmp-1),s[l+1]+=b*(tmp-1);
for(i=tmp;i<44;++i)
{
s[l-1]+=b,s[l]+=a,s[l+1]+=b,t[l]=i;
dfs(l+1,sum+i);
}
s[l-1]-=b*(i-1),s[l]-=a*(i-1),s[l+1]-=b*(i-1);
}
int main()
{
while(~scanf("%d%d%d",&n,&a,&b))
{
for(i=1;i<=n;++i)
scanf("%d",&h[i]);
ans=2e9;
memset(s,0,sizeof(s));
memset(t,0,sizeof(t));
dfs(2,0);
printf("%d\n",ans);
for(i=2;i<n;++i)
while(out[i]--)printf("%d ",i);
puts("");
}
return 0;
}
第5题:给你n本书,问最长的区间,使得区间内最高的书与最矮的书的高度差不超过n的最大长度,还有这样长度的区间有哪几个。。。
分析:看到n的范围,应该都知道至少要O(nlogn)的算法,普通的方法就是枚举区间两个端点,[i,j]然后判断这个区间是否满足条件,这样明显超时了,由于题目的特殊行,如果[i,j]满足条件,那么[i+1,j]必然满足条件,这个有什么用呢?我们每次整加i的时候,不用重新枚举j的范围了,呵呵,但是问题又来了,刚才那种方法可以在枚举j的时候找到最值,现在怎么办?当然得用线段树之类的区间最值求法了。。。
所以方案就是枚举加线段树,哈哈
代码:
#include<cstdio>
#include<iostream>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int mm=111111;
int ma[mm<<2],mi[mm<<2],ql[mm],qr[mm];
int i,j,k,n,ans,t;
void build(int l,int r,int rt)
{
if(l==r)
{
scanf("%d",&ma[rt]);
mi[rt]=ma[rt];
return ;
}
int m=(l+r)>>1;
build(lson);
build(rson);
ma[rt]=max(ma[rt<<1],ma[rt<<1|1]);
mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
}
int queryma(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)return ma[rt];
int m=(l+r)>>1,ret=0;
if(L<=m)ret=max(ret,queryma(L,R,lson));
if(R>m)ret=max(ret,queryma(L,R,rson));
return ret;
}
int querymi(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)return mi[rt];
int m=(l+r)>>1,ret=2e9;
if(L<=m)ret=min(ret,querymi(L,R,lson));
if(R>m)ret=min(ret,querymi(L,R,rson));
return ret;
}
int main()
{
while(~scanf("%d%d",&n,&k))
{
build(1,n,1);
ans=t=0;
for(i=j=1;j<=n;++i)
{
if(j<i)j=i;
while(j<=n&&(queryma(i,j,1,n,1)-querymi(i,j,1,n,1)<=k))++j;
if(j-i>ans)ans=j-i,ql[0]=i,qr[0]=j-1,t=1;
else if(j-i==ans)ql[t]=i,qr[t++]=j-1;
}
printf("%d %d\n",ans,t);
for(i=0;i<t;++i)printf("%d %d\n",ql[i],qr[i]);
}
return 0;
}