牛客练习赛38 部分题解

 

A出题人的RP值

链接:https://ac.nowcoder.com/acm/contest/358/A


来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

众所周知,每个人都有自己的rp值(是个非负实数),膜别人可以从别人身上吸取rp值。

然而当你膜别人时,别人也会来膜你,互膜一段时间后,你们就平分了两人原有的rp值,当你膜过一个人之后,你就不能再膜那个人了

出题人发现自己的rp值为x,出题人周围有n个人,第i个人的rp值为a[i]

你要选择膜哪些人和膜人的顺序,使出题人的最终rp值最大

 

输入描述:

第一行两个数n,x,人数和出题人的初始rp值
第二行n个数,第i个数a[i]表示第i个人的rp值

输出描述:

一行一个数表示出题人的最终rp值(保留三位小数)

示例1

输入

复制

1 0
1

输出

复制

0.500

备注:

数据范围:
n<=100000,a[i]<=100000,x<=100000,(a[i],x都是整数)

分析:首先可以要膜比原来大的,比原来值小的直接pass,第二,要按照从小到大排序(举两个值一算就ok)

((x+a)/2+b)/2=(x+a)/4+b/2

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e5+5;
 
int n;
double x,a[N];
 
int main()
{
    scanf("%d%lf",&n,&x);
    for(int i=1;i<=n;i++)
        scanf("%lf",&a[i]);
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++)
    {
        double tmp=(x+a[i])/2.0;
        if(tmp>x)
        {
            x=tmp;
        }
    }
    printf("%.3lf",x);
    return 0;
}

B: 出题人的女装

链接:https://ac.nowcoder.com/acm/contest/358/B
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

出题人早上起床就打算穿衣服,他有两箱衣服,因为懒,他在这两天只打算打开一个箱子.

两个箱子中一个有n件衣服,其中有x件女装,另一个有m件衣服,其中有y件女装.

出题人在第一天随机挑一个箱子后,接下来的两天就会从此箱子中随机找一件衣服穿.

又因为出题人懒而且很有钱,所以他穿完衣服后不会去洗,而是直接扔进垃圾桶,也不会放回原来的箱子.

已知出题人第1天穿了女装,求他第二天依然穿女装的概率

 

输入描述:

第一行包含5个整数n,m,x,y,t

输出描述:

若t=0,则在第一行输出概率(四舍五入保留小数点后3位,概率为0输出0.000,概率为100%输出1.000)
若t=1,则在第一行输出概率(最简分数形式,概率为0输出0/1,概率为100%输出1/1)

示例1

输入

复制

10 10 8 8 1

输出

复制

7/9

备注:

2<=n,m<=10000
2<=x<=n且2<=y<=m

贝叶斯公式

官网题解

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll a[1000000];
ll gcd(ll a,ll b) { return b == 0 ? a : gcd(b, a % b); }
int main()
{
    ll n,m,x,y,t;
    cin>>n>>m>>x>>y>>t;
    if(t==0)
    {
        double a=x*(x-1)*m*(m-1)+y*(y-1)*n*(n-1);
        double b=(n-1)*(m-1)*(x*m+n*y);
        printf("%0.3lf\n",a*1.0/b);
    }
    else{
       ll a=x*(x-1)*m*(m-1)+y*(y-1)*n*(n-1);
        ll b=(n-1)*(m-1)*(x*m+n*y);
        
        if(a==0){
            cout<<"0/1";
        }
        else if(a==b){
            cout<<"1/1";
        }else{
        	
            ll k=gcd(a,b);
            a/=k;
            b/=k;
            cout<<a<<"/"<<b<<endl;
        }
    }

    return 0;
}

D出题人的手环

链接:https://ac.nowcoder.com/acm/contest/358/D
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

出题人的妹子送了出题人一个手环,这个手环上有 n 个珠子,每个珠子上有一个数。

有一天,出题人和妹子分手了,想把这个手环从两个珠子间切开,并按顺时针顺序展开成一条链。

可以发现,这条链一共有 n 种可能性。求这 n 种可能性的逆序对数之积模 1000000007。

输入描述:

第一行一个数 n,表示珠子个数。
接下来一行 n 个数,以顺时针顺序给出每个珠子上的整数

输出描述:

一个数,表示答案。

示例1

输入

复制

4
1 3 2 3

输出

复制

24

说明

一共有 4 种方式:
1 3 2 3;3 1 3 2;2 3 1 3;3 2 3 1;
逆序对数分别为 1,3,2,4,积为 24。

备注:

n<=200000,-10^9<=珠子上的整数<=10^9。

分析:

离散化+树状数组+规律,具体思路:https://blog.csdn.net/sdz20172133/article/details/86363864

但这题和那一题稍微不同,上一题是0~n-1的全排列,所以,没有重复的数,但是这题可能有,所以这题的那个使用规律时,很难确定比某个数大的数有多少,比某个数小的数有多少,我的思路为:num[i]为i的个数(i是离散化后的对应的位置,注意离散化不去重),比他大的个数:n-num[i]-i+1,比他小的数就为i个。

#include<stdio.h>
#include<string>
#include<string.h>
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const int mod=1000000007;

const int MAXN=200000+5;//最大元素个数
int n;//元素个数
ll c[MAXN],a[MAXN];//c[i]==A[i]+A[i-1]+...+A[i-lowbit(i)+1]
ll b[MAXN];
//返回i的二进制最右边1的值
int lowbit(int i)
{
    return i&(-i);
}
//返回A[1]+...A[i]的和
ll sum(int x){
    ll sum = 0;
    while(x){
        sum += c[x];
        x -= lowbit(x);
    }
    return sum;
}
//令A[i] += val
void add(int x, ll val){
	
    while(x <= n){
        c[x] += val;
        x += lowbit(x);
    }
}
int num[MAXN];
int main()
{
	
	while(scanf("%d",&n)!=-1)
	{
		
		memset(c,0,sizeof(c));
		memset(num,0,sizeof(num));
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&a[i]);
			b[i]=a[i];
		}	
		sort(b+1,b+n+1);
		ll ans=0;
		int sum1=1;
		for(int i=n;i>0;i--)
		{
			int pos=lower_bound(b+1,b+n+1,a[i])-b;
			num[pos]++;
			ans=(ans+sum(pos-1))%mod;
			add(pos,1);
		}
		
		ll sum=ans;
	     //cout<<ans<<endl;
		for(int i=1;i<n;i++)
		{
			int pos=lower_bound(b+1,b+n+1,a[i])-b;
			ans=(ans+(n-pos-num[pos]+1)-(pos-1)+mod)%mod;///不要忘了+mod
			//cout<<a[i]<<" "<<n-pos-num[pos]+1<<" "<<pos-1<<endl;
			//cout<<ans<<endl;
			sum=(sum*ans)%mod;
		}
		cout<<sum<<endl;
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值