2020 年百度之星·程序设计大赛 - 初赛三

Discount

 传送门
 
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

学皇来到了一个餐馆吃饭。他觉得这家餐馆很好吃,于是就想办个会员。

一共有 nn 种会员充值卡套餐,假设学皇这餐饭的消费为 aa 元,选择第 ii 种套餐,需要充值 b[i] * ab[i]a 的钱,这次吃饭可以打 c[i]\times 10c[i]×10 折,由充值的钱支付(即这次吃饭只需要从充值金额中扣除 a\times c[i]a×c[i] 元)。以后用剩余的充值的钱吃饭不再打折。

请问学皇应该选择哪个套餐(必须选择恰好一个套餐),使得优惠的比例最大?

优惠比例的定义是把充的钱用完以后,(本来应该付的钱 - 实际付的钱) / 本来应该付的钱。在这个题目里,实际付的钱就是这次充值的花费。

Input

第一行一个整数 test(1test100) 表示数据组数。

对于每组数据,第一行一个正整数 n(1n100) 表示套餐的数目。

接下来 nn 行,每行一个正整数 b[i](1b[i]100) 和一个小数1c[i](0c[i]1,c[i]最多包含两位小数)。

Output

对于每组数据,输出一个五位小数表示最大的优惠比例。如果小数点后超过五位,四舍五入到五位。

Sample Input
1
2
2 0.5
3 0.1
Sample Output
0.23077

样例解释
对于第一种套餐,优惠比例为 0.5a / (2a + 0.5a) = 0.2;
对于第二种套餐,优惠比例为 0.9a / (3a + 0.9a) = 9 / 39;
 
 
 
解题思路:题目已经说的很明白了,把计算得公式都写出来了,所以直接套公式,把每种优惠得比例算出来,然后取最大即可。
AC代码:
#include<cstdio>
#include<iostream>
using namespace std;
#define maxn 105
int main(void)
{
    int t,n;
    double b,c;

    scanf("%d",&t);
    while(t--)
    {
            double sum=0;
        scanf("%d",&n);
        for(int i=0;i<n;++i)
        {
            scanf("%lf%lf",&b,&c);
            sum=max(sum,(1.0-c)/(b-c+1.0));//计算并取最大优惠的情况
        }
        printf("%.5lf\n",sum);
    }
    return 0;
}

 

 

Game

 传送门
 
 Time Limit: 4000/2000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

Alice 和 Bob 在玩游戏。

桌面上有两堆金币,少的那堆有 x 个金币,多的那堆有 2x 个金币。

假设金币可以被无限细分。Alice 和 Bob 事先都不知道 xx 是几,但是他们都知道 xx 是一个 (0, 1]之间均匀分布的随机实数。

Alice 会等概率的被分配到其中的一堆金币,Bob 会得到另一堆。x 的值和两堆金币的分配是相互独立的。

拿到金币以后,Alice 会马上数清自己拿到多少金币。然后 Alice 可以选择是否和 Bob 那堆换。

给定 Alice 拿到的金币数目,请问 Alice 要不要交换,使得她期望能得到的金币数目更多?

如果交换期望得到的金币数目多于不交换期望得到的金币数目,输出交换,否则不交换。

Input

第一行一个正整数 test (1test200000) 表示数据组数。

接下来每行一个小数 p (0<p2),p 最多保留五位小数,表示 Alice 拿到的金币数目。

Output

对于每组数据,输出 Yes 表示需要交换,输出 No 表示不要交换。

Sample Input
1
1.00000
Sample Output
Yes
 

解题思路:因为x是(0,1]的,p是(0,2]的,又由于当p>1的时候Alice肯定是拿的大的部分不用换,

否则Alice可能拿的大的可能拿的小的,算出来的期望值为1.25x>x,所以肯定换。

AC代码:

#include<cstdio>
#include<iostream>
using namespace std;
#define maxn 105
int main(void)
{
    int t;
    double p;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lf",&p);
        if(p<=1)
        puts("Yes");
        else
        puts("No");
    }
    return 0;
}

 

Permutation

 传送门
 
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

一开始有 nn 个数,他们按 1...n1...n 的顺序排列,要求交换最多 mm 对数字(同一个数字可以参与多次交换),使得逆序对数目最大。

对于一个序列 AA,如果存在正整数 i, j使得 1i<jn 而且 A[i] > A[j],则A[i], A[j] 这个有序对称为 A 的一个逆序对。

Input

第一行一个正整数 test (1test100000) 表示数据组数。

对于每组数据,一行两个整数nm (1n1000000,0m1000000) 表示数字个数和最多可以交换的数字对数。

Output

对于每组数据,一行一个整数表示答案。

Sample Input
6
1 1
2 0
2 1
3 1
4 1
4 2
Sample Output
0
0
1
3
5
6
 
解题思路:这道题我们要让逆序对最多,一定是按照第一个和最后一个交换,第二个和倒数第二个交换。。。。
很显然我们发现这样的交换只能做n/2次(向下取整)。然后我我们可以观察每次交换能得到的逆序对数。

 

好了,我们已经发现了4的规律,我们猜测是不是5也是呢?

 

聪明的你一定发现了什么,我们可以看到n为偶数和n为奇数的情况是不相同的,n为偶数的时候结尾只有1,而n为奇数的时候结尾是3,

而逆序对数,最多就为(n-1)*n/2对,我们可以让sum先等于最多的对数,然后根据m的数减去相应的数就行,我们可以发现其实n为奇数和n为偶数

是两个不同的序列,但是公差都为4,n为奇数的首项为3,n为偶数的首项为1,然后。。。。。,然后就AC了鸭!(可惜比赛的时候写错了,然后wa了好几发)

AC代码:

#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
int main(void)
{
    ll t;
    ll n,m;
    ll sum,k;
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld%lld",&n,&m);
        sum=(n-1)*n/2;
        if(m<n/2)
        { 
            k=(n/2-m);
            if(n&1)
            sum-=(2*k+1)*k;//前k项和
            else
            sum-=(2*k-1)*k;//前k项和
        }
        printf("%lld\n",sum );
    }
    return 0;
}

 

Intersection

传送门

 Time Limit: 4000/2000 MS (Java/Others)
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

Mr. Left 来到了一个路口,这个路口只能右转,并且都是两车道。

现在在南北向车道上有 n 辆车,他们都在线 x 南边,这些车想要通过这个路口,到东边去,具体地说,他们要开到线 y 东边。

一辆车一个时刻可以从东南西北中选一个方向移动一个位置,或者呆在原地不动。 同一时刻同一位置不能有超过一辆车。车不能开到路外面。

在任意时刻,所有车都同时移动。两辆相邻的车不能都移动到对方的格子上。在此基础上,只要所有车移动后不存在两辆车处于同一位置,移动就合法。

问最少要多少时间,这些车才可以都开到东边?

Input

第一行一个整数 test (1test10)。

对于每组数据,第一行一个整数 n (1n100000),表示车辆数目。

接下来 n 行,每行两个整数xy 表示车的位置,其中 x 表示车道 id( x=1 表示右车道,x=2 表示左车道),y (1y100000) 表示车在路口前第几个位置。

数据保证没有两辆车初始在同一位置。

Output

对于每组数据,一行一个整数表示答案。

Sample Input

2
2
1 1
2 1
2
1 2
2 1
Sample Output4
样例解释
第一组
time 0
....
....
CC
..
time 1
....
CC..
..
..
time2
....
.CC.
..
..
time3
....
..CC
..
..
第二组
time 0
....
....
C.
.C
time 1
....
C...
.C
..
time2
C...
.C..
..
..
time3
.C..
..C.
..
..
time4
..C.
...C
..
..

解题思路:可能会有人以为这个搜索题,但是看下数据会发现这完全搜不了,所以这是一道模拟题,我们知道一辆车从右车道起始位置到达线y的东边(也就是y的右边)的最短距离是y+1,左车道为y+2

那么我们就直接每次算出来当前车到达目的地的距离,左车道和右车道是分开的,那么我们就定义两个变量l和r分开计算车的最大位移,细心一想我们不难发现会存在两辆车会存在同一时间在同一个位置的情况

通过样例2我们也不难发现,当存在撞车情况的时候我们只需要让左车道的车多走一步(走外面那个圈)就能避免撞车情况。

AC代码:
#include<cstdio>
int max(int a,int b)
{
    return a>b?a:b;
}
int l,r,t,n,x,y;
int main(void)
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        l=r=0;
        for(int i=0;i<n;++i)
        {
            scanf("%d%d",&x,&y);
            if(x==1)//把右车道最小距离算出来
                r=max(r,y+1);
            else//把左车道对小距离算出来
                l=max(l,y+2);
        }
        if(l==r)//判断是否会撞车
        r++;
        else
        r=max(l,r);
        printf("%d\n",r);
    }
    return 0;
}

%%%%


posted @ 2020-07-26 22:15  MangataTS  阅读(297)  评论(0编辑  收藏  举报