题解:牛客小白月赛102(A - C)

A 序列中的排列

题意:

每次给你两个正整数 n , k n,k n,k ,并给你一段长度为 n n n 的序列。(所有输入均为小于等于100的正整数)
问:原序列中是否存在子序列,使得这个子序列是 k k k 的排列
子序列:某个序列的子序列是从最初序列通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新序列。
排列:一个 k k k 的排列是一个长度为 k k k 的整数序列,其中包含了从 1 1 1 k k k 的每个数字,每个数字仅出现一次。

做法:

只要找到序列中是否存在 1 ∼ k 1 \sim k 1k 的每一个数即可
可以使用计数数组(数据范围也不大)

代码:

#include <iostream>
#include <algorithm>
#include <map>

void solve() {
    int max = -1;
    int n,m,num,cnt = 0;
    std::cin >> n >> m;
    std::map<int,int> mp;
    for(int i = 0 ; i < n ; i ++) {
        std::cin >> num;
        if(num <= m && !mp.count(num)) cnt ++,max = std::max(max,num);;
        mp[num] ++;
    }
    std::cout << (max == m && cnt == m ? "YES\n" : "NO\n");
}

signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    std::cout.tie(0);

    int t = 1;
    std::cin >> t;
    while(t--) solve();
    return 0;
}

B 连分数

题意:

(有点抽象,我直接放原文吧)

给定 a a a ,定义
x = a + 1 a + 1 a + 1 a + … x = a + \frac{1}{a+\frac{1}{a+\frac{1}{a+\dots}}} x=a+a+a+a+111

x x x 的值。

形式上说,设 f ( n ) = { a n = 1 a + 1 f ( n − 1 ) n > 1 f(n) = \left\{\begin{matrix} a & n=1\\ a+\frac {1}{f(n-1)} & n>1\end{matrix}\right. f(n)={aa+f(n1)1n=1n>1 x = lim ⁡ n → + ∞ f ( n ) x=\lim_{n \to + \infty}f(n) x=limn+f(n),求 x x x 的值。

a a a 是浮点数且是正实数,不超过 1 0 5 10^5 105 x x x 精确到小数点后 9 9 9 位)

做法1及其代码:

大家都学过极限,了解了极限的思想,那这题我们就好做了
首先,当 n n n 趋近于正无穷时, f ( n ) f(n) f(n) 一定趋近于某一个数,这样子才有一个解
正因如此,假设 f ( n ) f(n) f(n) 趋近于某一个数成立,那我们可以把 f ( n ) f(n) f(n) f ( n − 1 ) f(n-1) f(n1) 视作等价的(之间的差值忽略不计)

于是我们可以列出以下式子
x = a + 1 x x = a + \frac{1}{x} x=a+x1
移项得(易证 x x x 不等于 0 0 0):
x 2 − a x − 1 = 0 x^2 - ax - 1 = 0 x2ax1=0

于是我们只要找出这个 x x x 的近似解即可

如果我们会求根公式的话,就可以求根公式直接上了

#include <bits/stdc++.h>
#define int long long
#define INF 0x3f3f3f3f

void solve() {
    double a;
    std::cin >> a;
    printf("%.10f\n",(a +  sqrt(a*a + 4)) / 2);
}

signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);

    int t = 1;
    std::cin >> t;
    while(t--) solve();
    return 0;
}

如果不会求根公式的话,也没关系。
不难看出, x x x 的值随着 a a a 的值递增而递增
于是我们可以进行实数二分
最小值设置个 1 1 1 就好了,最大值可以设置 100001 100001 100001(最后一个样例告诉我们不会超过这个数)

#include <bits/stdc++.h>
#define int long long
#define INF 0x3f3f3f3f

const double eps = 1e-9;

void solve() {
    double a;
    std::cin >> a;
    double l = 1,r = 1e5 + 1;
    while(fabs(l-r) >= eps) {
        double mid = (l + r) / 2;
        if(mid * mid - a * mid - 1 >= 0) r = mid;
        else l = mid;
    }
    printf("%.10f\n",l);
}

signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);

    int t = 1;
    std::cin >> t;
    while(t--) solve();
    return 0;
}

做法2及其代码:

如果说,我没想到上面的思想,能不能模拟?
可以!
但是要做一点小运算
举个例子:

因为是第一个是 a a a
第二个不就是 a + 1 a a + \frac{1}{a} a+a1
你手动模拟下就发现
每一次的值都是:前面得到的分数分子分母互换,然后分子加上分母的 a a a

ok,然后我们直接写就可以了

#include <bits/stdc++.h>
#define int long long
#define INF 0x3f3f3f3f

const double eps = 1e-9;

void solve() {
    double a;
    std::cin >> a;
    double fz = a,fm = 1,c = fz / fm;
    std::swap(fz,fm);
    fz += fm*a;
    while(fabs(c - fz / fm) > 1e-10) {
        c = fz / fm;
        std::swap(fz,fm);
        fz += fm*a;
    }
    printf("%.10f\n",fz/fm);
}

signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);

    int t = 1;
    std::cin >> t;
    while(t--) solve();
    return 0;
}

C sum

题意:

给你 n , s u m n,sum n,sum 和序列 a a a
已知有 n n n 个数 a i a_i ai ,你可以进行若干次修改操作,每一次操作任意修改一个数的值为 x ( − 1 0 4 ≤ x ≤ 1 0 4 ) x(-10^4 \le x \le 10^4) x(104x104)
问最少多少次操作使得这 n n n 个数的和为 s u m sum sum

做法:

很经典的贪心,总和比 s u m sum sum 大就把最大的尽可能变小,总和比 s u m sum sum 小就把最小的尽可能变大,直到跨越 s u m sum sum 为止。

代码:

#include <bits/stdc++.h>
#define int long long
#define INF 0x3f3f3f3f
#define all(x) x.begin(),x.end()

void solve() {
    int n,m,sum = 0,ans = 0;
    std::cin >> n >> m;
    std::vector<int> a(n);
    for(int i = 0 ; i < n ; i ++) std::cin >> a[i],sum += a[i];
    std::sort(all(a));
    if(sum == m) std::cout << 0 << "\n";
    else if(sum > m) {
        for(int i = n-1 ; i >= 0 ; i --) {
            ans ++;
            if(sum - (a[i] + 1e4) <= m) break;
            sum -= (a[i] + 1e4);
        }
        std::cout << ans << "\n";
    } else {
        for(int i = 0 ; i < n ; i ++) {
            ans ++;
            if(sum + (1e4 - a[i]) >= m) break;
            sum += (1e4 - a[i]);
        }
        std::cout << ans << "\n";
    }
}

signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);

    int t = 1;
    std::cin >> t;
    while(t--) solve();
    return 0;
}

文章转载自博客https://www.cnblogs.com/jiejiejiang2004/p/18461306
博主已同意,我就是博主

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值