NEFU要崛起——第5场

比赛地址: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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值