信息学奥赛一本通【02NOIP提高组】题解

目录

1828:【02NOIP提高组】均分纸牌

【题目描述】

【输入】

【输出】

【输入样例】

【输出样例】

1829:【02NOIP提高组】自由落体

【题目描述】

【输入】

【输出】

【输入样例】

【输出样例】

1830:【02NOIP提高组】矩形覆盖

【题目描述】

【输入】

【输出】

【输入样例】

【输出样例】


1828:【02NOIP提高组】均分纸牌


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 1174     通过数: 919

【题目描述】

有N堆纸牌,编号分别是1,2,3,...N。每堆上有若干张,但纸牌总数必为N的倍数。可以在任一堆上取若干张纸牌,然后移动。移牌规则为:在编号为1的堆上取的纸牌,只能移到编号为2的堆上;在编号为N的堆上取的牌只能移到编号为N-1的堆上;其余堆上取的纸牌,可以移到相邻左边或右边的堆上。现在要求找出一种移动方法,用最少的移动次数使每堆纸牌数都一样多。例如N=4,4堆纸牌数分别为:

①9 ②8 ③17 ④6

移动3次可达到目的:从 ③取4张牌放到④(9 8 13 10)-->从③取3张牌放到②(9 11 10 10)-->从②取1张牌放到 ①(10 10 10 10)。

【输入】

N (N堆纸牌,1≤N≤100)

A1,A2,...,An(N堆纸牌.每堆纸牌初始数,1≤Ai≤10000)

【输出】

所有堆均达到相等时的最少移动次数。

【输入样例】

4
9 8 17 6

【输出样例】

3

题解:

#include<cstdio>
#define maxn 100005
using namespace std;
int n,sum=0,mid,ans=0;
int a[maxn];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        sum+=a[i];
    }
    mid=sum/n;

    for(int i=1;i<=n;i++)
    {
        if(a[i]>mid) a[i+1]+=a[i]-mid,ans++;
        if(a[i]<mid) a[i+1]-=mid-a[i],ans++;
    }
    printf("%d",ans);
    return 0;
}

1829:【02NOIP提高组】自由落体


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 594     通过数: 204

【题目描述】

在高为H的天花板上有n个小球,体积不计,位置分别为0,1,2,...。在地面上有一个小车(长为L,高为K,距原点距离为S1)。已知小球下落距离计算公式为s=1/2*g*t2,其中g=10,t为下落时间。地面上的小车以速度V前进。如图:

小车与所有小球同时开始运动,当小球距小车的距离≤0.00001时,即认为小球被小车接受(小球落到地面后不能被接受)。请你计算出小车能接受到多少个小球。

【输入】

H,S1,v,L,k,n (1≤H,S1,v,L,k,n≤100000,各个数之间用一个空格隔开)

【输出】

小车能接受到的小球个数。

【输入样例】

5.0 9.0 5.0 2.5 1.8 5

【输出样例】

1

题解:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define eps 1e-5
#define rps 1e-6
using namespace std;
double H,S1,V,L,K;
int n;
int main()
{
    scanf("%lf%lf%lf%lf%lf%d",&H,&S1,&V,&L,&K,&n);
    double yu=S1-sqrt(H/5.0)*V-eps;int p=(int)yu;
    if(yu-p>rps) p++;
    double y=H-K-sqrt(eps);y=max(0.0,y);
    y=S1+L-sqrt(y/5.0)*V+eps;int q=(int)y;
    p=max(p,0);q=min(n-1,q);
    printf("%d",max(0,q-p+1));
}

 

1830:【02NOIP提高组】矩形覆盖


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 235     通过数: 171

【题目描述】

在平面上有n个点(n≤100),每个点用一对整数坐标来表示。例如:当n=4时,4个点的坐标分别为:P1(1,1),P2(2,2),P3(6,3),P4(7,0)

这些点可以用k个矩形(k<4)全部覆盖,矩形的边平行于坐标轴。如图一,当k=2是,可用如图二的两个矩形s1,s2覆盖,s1,s2面积和为4。问题是当n个点坐标和k给出后,怎样才能使得覆盖所有点的k个矩形的面积之和为最小呢。约定:

◇ 覆盖一个点的矩形面积为0;

◇ 覆盖平行于坐标轴直线上点的矩形面积也为0;

◇ 各个矩形间必须完全分开(边线也不能重合);

【输入】

第一行为n和k,接下来为n行,每行两个数,中间用空格隔开,且0≤xi,yi≤500

【输出】

一行,一个整数,即满足条件的最小的矩形面积之和。

【输入样例】

4 2
1 1
2 2
6 3
7 0

【输出样例】

4

题解:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#define INF 1e7
using namespace std;
int n,k;
struct node{
    int x,y;
}sa[60];
struct node2{
    node l,r;
}sb[10];
int ans=INF;
bool checkit(int i,int j)
{
    if(sb[i].l.x==INF||sb[i].l.y==INF||sb[i].r.x==-INF||sb[i].r.y==-INF)  
        return 0;  
    if(sb[j].l.x==INF||sb[j].l.y==INF||sb[j].r.x==-INF||sb[j].r.y==-INF)  
        return 0;  
    if(sb[i].l.x>sb[j].r.x||sb[i].l.y>sb[j].r.y)  
       return 0;  
    if(sb[j].l.x>sb[i].r.x||sb[j].l.y>sb[i].r.y)  
       return 0;  
    return 1;  
}
bool check()
{
    for(int i=1;i<=k;i++)
    {
        for(int j=i+1;j<=k;j++)
        {
            if(checkit(i,j)) return 0;
        }
    }
    return 1;
}
int getsqr()
{
    int ans1=0;
    for(int i=1;i<=k;i++)
    {
        if(sb[i].l.x!=INF)
        {
            ans1+=(sb[i].r.x-sb[i].l.x)*(sb[i].r.y-sb[i].l.y);
        //  printf("%d %d\n",(sb[i].r.x-sb[i].l.x),(sb[i].r.y-sb[i].r.y));
        }

    }
    return ans1;
}
void dfs(int now)
{
    //printf("%d\n",now);
    if(now==n+1)
    {
        ans=getsqr(); 
        return;
    }
    int x=sa[now].x,y=sa[now].y;

    for(int i=1;i<=k;i++)
    {
        node2 tmp=sb[i];
    /*  sb[i].l.x=min(sb[i].l.x,x);
        sb[i].l.y=min(sb[i].l.y,y);
        sb[i].r.x=max(sb[i].r.x,x);
        sb[i].r.y=max(sb[i].r.y,y);*/
         if(sb[i].l.x>sa[now].x)  
           sb[i].l.x=sa[now].x;  
       if(sb[i].l.y>sa[now].y)  
           sb[i].l.y=sa[now].y;  
       if(sb[i].r.x<sa[now].x)  
           sb[i].r.x=sa[now].x;  
       if(sb[i].r.y<sa[now].y)  
           sb[i].r.y=sa[now].y; 
        if(check()&&getsqr()<ans)
        dfs(now+1);
        sb[i]=tmp;
    }
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    scanf("%d%d",&sa[i].x,&sa[i].y);
    for(int i=1;i<=k;i++)
    {
        sb[i].l.x=sb[i].l.y=INF;
        sb[i].r.x=sb[i].r.y=-INF;
    }
    dfs(1);
    printf("%d\n",ans);
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值