笔试DAY5

**重叠的装饰

市长的海报
牛客网的一些解答
线段树
题目描述:
我们部门需要装饰墙,但是墙非常非常的长,有一千万米。我们会按顺序贴很多海报在上面,这些海报相互之间会重叠,请问下,最后还能看到哪些?(只看到一部分也算)

输入描述:
N表示N张海报
接下来每一行代表海报的左右边界(上下默认全满),Li,Ri,均为整数,大于0,小于一千万。海报按输入顺序张贴。
输出描述:
有多少张海报是可见的
在这里插入图片描述

排队唱歌

题目描述:
我们部门要排队唱歌,大家乱哄哄的挤在一起,现在需要按从低到高的顺序拍成一列,但每次只能交换相邻的两位,请问最少要交换多少次

输入描述:
第一行是N(N<50000),表示有N个人
然后每一行是人的身高Hi(Hi<2000000,不要怀疑,我们以微米计数),持续N行,表示现在排列的队伍
输出描述:
输出一个数,代表交换次数。
在这里插入图片描述
求逆序对数

#include<bits/stdc++.h>
using namespace std;
 
int main()
{
   
    int n, i, j, ans = 0, temp;
    cin >> n;
    vector<int> a(n);
    for(i = 0; i < n; i++)
        cin >> a[i];
    for(i = 0; i < n; i++)
        for(j = 0; j < i; j++)//****
            if(a[j] > a[i])
                ans++;
    cout << ans << endl;
    return 0;
}

使用bisect模块,创建新的有序数组,数字在原数组中的位置与新的有序数组中的位置差,即为移动次数。其中,通过bisect.bisect_left() 返回插入的位置。通过 bisect.insort()插入数组并排序。

import bisect
n = int(input())
nums = []
for _ in range(n):
  nums.append(int(input()))
result = 0
lst = [nums[0]]
for i in range(1, n):
  idx = bisect.bisect_left(lst, nums[i])
  bisect.insort(lst, nums[i])
  result += i - idx  
print(result)

**K点游戏

动态规划法
leetcode
牛客网解答
题目描述:
小招喵某日闲来无事,想验一下自己的人品,于是给自己定了一个游戏规则:
这个游戏有三个因素:N,K,W
游戏开始的时候小招喵有0点,之后如果发现自己手上的点不足K点,就随机从1到W的整数中抽取一个(包含1和W),抽到哪个数字的概率都是相同的。
重复上述过程,直到小招喵获得了K或者大于K点,就停止获取新的点,这时候小招喵手上的点小于等于N的概率是多少?

输入:N = 5, K = 1, W = 5
输出:1.00000
说明:开始有0点,不足1点,从[1,5]中随机取一个整数(一共5个数字,所以每个数字取到的概率都是1/5),获得后得分无论如何都大于了1点,停止,概率为1

输入:N = 6, K = 1, W = 10
输出:0.60000
说明:开始有0点,不足1点,从[1,10]中随机取一个整数(一共10个数字,所以每个数字取到的概率都是1/10),获得后有6/10的概率小于6点,且满足大于1点的条件,概率为0.6
输入描述:
输入为3个整数,分别对应N,K,W,中间用空格隔开

其中0 <= K <= N <= 10000,1 <= W <= 10000
输出描述:
输出为概率值,保留5位小数
在这里插入图片描述
由题目要求知道,N是点数的上限,K是点数的下限,W是随机取点数的上限。
动态规划:设 dp[i] 是初始点为 i 时的符合题目要求的概率。
当初始点 i 位于 [K,N] 时,此时的 dp[i] =1。
当初始点 i 位于 [N+1,K−1+W] 时 ,此时的dp[i]=0 。
关键的递归是:
在这里插入图片描述
通过这种递归,我们可以做一个朴素的动态编程解决方案,如下所示:

#psuedocode
dp[k] = 1.0 when K <= k <= N, else 0.0
# dp[x] = the answer when Alice has x points
for k from K-1 to 0:
    dp[k] = (dp[k+1] + ... + dp[k+W]) / W
return dp[0]

但是这导致 O(K*W + (N-K)) 的时间复杂度,每个计算dp[k]需要O(W),但是工作非常相似。但实际上,
在这里插入图片描述
所以我们可以维持一个变量S=dp(i+1)+dp(i+2)+⋯+dp(i+W).
在这里插入图片描述
想要计算 dp[i−1],只需要在 dp[i] 的公式基础上加一项 dp[i],再减一项 dp[i+W] 即可。

两点疑问:
如何得出递推公式
为什么S = min( N - K + 1, W )

#include<iostream>
#include<vector>
#include<algorithm>
#include<iomanip>
using namespace std;
int main()
{
   
    int n,k,w;
    cin>>n>>k>>w;
    vector<float> dp(k+w);
    for(int i=k;i<=n;i++)
        dp[i]=1;
    for(int i=n+1;i<k+w;i++)
        dp[i]=0;
    float temp=min(w,n-k+1);//S
    for(int i=k-1;i>=0;i--)
    {
   
        dp[i]=temp/w;
        temp+=dp[i]-dp[i+w];
    }
    cout<<fixed<<setprecision(5)<<dp[0];
}
class Solution {
   
    public double new21Game(int N, int K, int W) {
   
        double[] dp = new double[N + W + 1];
        // dp[x] = the answer when Alice has x points
        for (int k = K; k <= N; ++k)
            dp[k] = 1.0;

        double S = Math.min(N - K + 1, W);
        // S = dp[k+1] + dp[k+2] + ... + dp[k+W]
        for (int k = K - 1; k >= 0; --k) {
   
            dp[k] = S / W;
            S += dp[k] - dp[k + W];
        }
        return dp[0];
    }
}
class Solution(object)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值