牛客小白月赛102

A题

题目描述

给定一组数,找出这组数的子序列中有一个包含从1~n的所有数字(此处子序列是从最初序列通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新序列)

用map记录每个数出现与否,再判断是否满足题意

代码

#include<bits/stdc++.h>
using namespace std;
int T,n,k,a[1005];
map<int,int> ma;
void ac(){
    ma.clear();
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        ma[a[i]]=1;
    }
    for(int i=1;i<=k;i++){
        if(!ma[i]){
            cout<<"NO"<<endl;
            return;
        }
    }
    cout<<"YES"<<endl;
    return;
}
int main(){
    T=1;
    cin>>T;
    while(T--){
        ac();
    }
}

B题

链接:https://ac.nowcoder.com/acm/contest/91355/B

当n趋于无穷是,原式变为x=a+$ \frac{1}{a} $,将x解出

代码

#include<bits/stdc++.h>
using namespace std;
int T;
double a;
void ac(){
    cin>>a;
    cout<<fixed<<setprecision(15);//确定保留位数
    cout<<(a + sqrtl(a * a + 4)) / 2<<endl;
}
int main(){
    T=1;
    cin>>T;
    while(T--){
        ac();
    }
    return 0;
}

C题

题意

有𝑛个数,你可以进行若干次修改操作,每一次操作任意修改一个数(-1e4~1e4),问最少多少次操作使得这 𝑛个数的和为sum。

思路

得出原数组得和,若比sum大,则从大的数开始修改为-1e4,若得到了ans<=sum,则可以经过修改得到sum,反之不能;

代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int T,n,sum,a[N];
map<int,int> ma;
void ac(){
    int ans=0;
    cin>>n>>sum;
    for(int i=0;i<n;i++){
        cin>>a[i];
        ans+=a[i];//记录当前数的和;
    }
    sort(a,a+n);//排序
    int cnt=0;
    if(ans==sum) cout<<"0"<<endl;
    if(ans>sum){//和比目标大,则从最大的数开始修改
        for(int i=n-1;i>=0;i--){
            if(ans-1e4-a[i]>sum){
                ans-=1e4+a[i];
                cnt++;
            }
            else{
                cnt++;
                cout<<cnt<<endl;
                break;
            }
        }
    }
    else if(ans<sum){
        for(int i=0;i<n;i++){
            if(ans-a[i]+1e4<sum){
                cnt++;
                ans+=1e4-a[i];
            }
            else{
                cnt++;
                cout<<cnt<<endl;
                break;
            }
        }
    }
}

int main(){
    T=1;
    cin>>T;
    while(T--){
        ac();
    }
}

D题

在一个无向图里,从点1到点n,LH到达n的最短时间,每个点休息时间为a[i],若不休息则花费1的时间休整就出发(起点1也要判断他休不休息),且连续不休息不能超过k次。

思路

分层图,用dis[i][j]来记录连续不休息j次到达i点所用的时间,其代价为1,若休息了,则j清零重新计数,代价为a[i],用dijkstra跑最短路,得到答案;

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5 + 5;
ll n, m, k, a[N], u, v;
map<ll, ll> ma;
struct node {
    ll u, now, cnt;//到达时间,现在到达的点,连续不休息的次数
};
bool operator<(node x, node y) {
    return x.u > y.u;
}//结构体优先队列
vector<ll> ve[N];
priority_queue<node> q;
ll flag[N][15], dis[N][15];

void dij(ll x) {
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= k; j++) {
            dis[i][j] = 1e18;
            flag[i][j] = 0;
        }
    }
    if (k != 0) {
        dis[x][1] = 1;
        q.push({ 1,x,1 });
    }
    dis[x][0] = a[x];
    q.push({ a[x],x,0 });
    while (!q.empty()) {
        auto t = q.top(); q.pop();
        ll w = t.now; ll nd = t.cnt; ll di = t.u;
        if (flag[w][nd]) continue;
        flag[w][nd] = 1;
        for (auto n : ve[w]) {
            ll e = n; ll f = a[n];//当前点,代价
            if (nd < k && dis[e][nd + 1]>di + 1 && !flag[e][nd + 1]) {//不休
                dis[e][nd + 1] = di + 1;
                q.push({ dis[e][nd + 1],e,nd + 1 });
            }
            if (dis[e][0] > di + f) {//休息
                dis[e][0] = di + f;
                q.push({ dis[e][0],e,0 });
            }
        }
    }
}

void ac() {
    cin >> n >> m >> k;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        ve[i].clear();
    }
    while (m--) {
        cin >> u >> v;
        ve[u].push_back(v);
        ve[v].push_back(u);//存边
    }
    dij(1);
    ll ans = 1e18;
    for (ll i = 0; i <= k; i++) {
        ans = min(ans, dis[n][i]);//比较得到答案
    }
    cout << ans << endl;
    return;
}
int main() {
    ll T = 1;
    cin >> T;
    while (T--) {
        ac();
    }
}
posted @ 2024-10-20 17:02  27hhhh  阅读(0)  评论(0编辑  收藏  举报