2023河南萌新联赛第(一)场:河南农业大学

2023河南萌新联赛第(一)场:河南农业大学_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ

C.硬币游戏

考察知识点:博弈

先说结论:若操作一次就能获胜则先手胜,若无论第一次怎么操作,第二次操作都能获胜则后手胜,否则平局

证明:对于上述结论中先手胜和后手胜的局面显而易见,无需证明,对于平局:处于劣势的一方,无论对手怎么操作,只需要复制对手的操作即可保证自己不会输掉,对于此时的另一方,无论怎么操作自己永远也不可能获胜,同时也可以按照上述操作保证自己不会输掉,所以一定会平局

判断一下即可,时间复杂度O(n)

所以只需要找出能够判断胜负的情况即可,其它情况都是平局

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<deque>
#include<vector>
using namespace std;
void solve()
{
    int n,k;
    cin>>n>>k;
    string s;
    cin>>s;
    int cnt=1;
    vector<int>pos;
    for(int i=1;i<s.size();i++){
        if(s[i]==s[i-1]) cnt++;
        else {
            pos.push_back(cnt);
            cnt=1;
        }
    }
    if(cnt) pos.push_back(cnt);
    if(pos.size()==1&&pos[0]<=k) puts("Alice");
    else if(pos.size()==1&&pos[0]>k) puts("Bob");
    else if(pos.size()==2&&(pos[0]<=k||pos[1]<=k)) puts("Alice");
    else if(pos.size()==3&&pos[1]<=k) puts("Alice");
    else if(s == "0101" || s == "1010" || s == "1100" || s == "0110" || s == "0011" || s == "1001") puts("Bob");
    else cout<<":(\n";
}
int main()
{
    solve();
    return 0;
}

D.松鼠回家

使得路径上扣除松果的数量最大的那个点扣除的数量尽可能小,想到用二分来寻找答案,如果用二分得到的数满足的话,就继续往小了找,如果不满足的话,就往大了找

路上所消耗的体力就和边权值是一个意思

对于每一个二分的答案,判断它是否合法,在保证其合法的情况下,找一条体力值尽可能小的路(最短路,这样体力值才能小于h)

用bfs求最短路,如果遇到更短的路径并且去的那个点要扣除的松果小于等于二分得到的数,那么就更新最短路径

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define int long long
using namespace std;
typedef pair<int,int>PII;
const int N=1e4+10;
int a[N];//扣除松果数量
int n,m,st,ed,h;
vector<PII>e[N];
int dist[N],vis[N];
bool bfs(int x)
{
    memset(dist,0x3f,sizeof dist);
    memset(vis,0,sizeof vis);
    priority_queue<PII,vector<PII>,greater<PII>>heap;
    dist[st]=0;
    heap.push({0,st});//把起点放进去
    while(heap.size()){
      auto t=heap.top();
      int d=t.first,ver=t.second;
      heap.pop();
      if(vis[ver]) continue;
       vis[ver]=1;
       for(auto v:e[ver]){
           int y=v.first,z=v.second;
        if(dist[y]>dist[ver]+z&&a[y]<=x){
            dist[y]=dist[ver]+z;
            heap.push({dist[y],y});
        }
     }
    }
    if(dist[ed]<=h) return true;
    return false;
}
void solve()
{
    cin>>n>>m>>st>>ed>>h;
    for(int i=1;i<=n;i++) cin>>a[i];
    while(m--){
        int x,y,z;
        cin>>x>>y>>z;
        e[x].push_back({y,z});
        e[y].push_back({x,z});
    }
    int l=1,r=1e7;
    while(l<r){
        int mid=(l+r)/2;
        if(bfs(mid)) r=mid;
        else l=mid+1;
    }
    if(bfs(l)) cout<<l<<endl;
    else cout<<-1<<endl;
}
signed main()
{
    solve();
    return 0;
}

E.动物朋友

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<deque>
#define int long long
using namespace std;
int n,m;
deque<int>q;
void solve()
{
    cin>>n>>m;
    int res=0;
    int sum=0;
    for(int i=0;i<n;i++){
        int x;
        cin>>x;
        sum+=x;
        q.push_back(x);
        if(sum==m) res++;
        while(sum>=m&&q.size()){
            int t=q.front();
            sum-=t;
            q.pop_front();
            if(sum==m) res++;
        }
    }
    cout<<res<<endl;
}
signed main()
{
    solve();
    return 0;
}

F.松鼠排序

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<deque>
#define int long long
using namespace std;
const int N=1e5+10;
int a[N];
void solve()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    int res=0;
    for(int i=1;i<=n;i++){
        while(a[i]!=i){
           swap(a[i],a[a[i]]);
           res++;
        }
    }
    cout<<res<<endl;
}
signed main()
{
    solve();
    return 0;
}

G.Reverse

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<deque>
#include<set>
#include<queue>
#define int long long
using namespace std;
void solve()
{
    int n;
    cin>>n;
    string s;
    cin>>s;
    s+='0';
    int cnt=0;
    priority_queue<int>q;
    for(int i=0;i<=n;i++){
        if(s[i]=='0') {
            q.push(cnt);
            cnt=0;
        }
        else if(s[i]=='1') cnt++;
    }
    int res=0;
    if(q.size()){
        int t=q.top();
        q.pop();
        res+=t;
    }
    if(q.size()){
        int t=q.top();
        q.pop();
        res+=t;
    }
    cout<<res<<endl;
}
signed main()
{
    solve();
    return 0;
}

H.迷宫探险

用bfs求最短路,先将起点放入队列

然后一层层拓展,遇到道路,则向四周拓展一步

遇到弹射器,则四个方向拓展x距离,只需看最后是否越出边界或者遇到墙壁 、

注意之前是通过标记位置表示已经走过,而已经走过则表示到这是最短距离

但是这里有弹射,所以走过并不代表是最短距离,所以这里比较和起点之间的距离大小

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
//#define int long long,以后不要轻易用这个了
using namespace std;
typedef pair<int,int>PII;
const int N=3010;
char s[N][N];
int d[N][N];
int len[N][N];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
int n,m,k;
void bfs(){
    queue<PII>q;
    memset(d,0x3f,sizeof d);
    d[1][1]=0;
    q.push({1,1});
    while(q.size()){
        auto t=q.front();
        q.pop();
        if(s[t.first][t.second]=='.'){
            for(int i=0;i<4;i++){
                int x=t.first+dx[i],y=t.second+dy[i];
                if(x&&y&&x<=n&&y<=m&&s[x][y]!='#'&&d[x][y]>d[t.first][t.second]+1){
                    d[x][y]=d[t.first][t.second]+1;
                    q.push({x,y});
                }
            }
        }
        else{
            for(int i=0;i<4;i++){
                int x=t.first+dx[i]*len[t.first][t.second];
                int y=t.second+dy[i]*len[t.first][t.second];
            if(x>=1&&y>=1&&x<=n&&y<=m&&s[x][y]!='#'&&d[x][y]>d[t.first][t.second]){
                d[x][y]=d[t.first][t.second];
                q.push({x,y});
            }
        }
        }
    }
}
void solve()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>s[i][j];
        }
    }
    cin>>k;
    while(k--){
        int x,y,z;
        cin>>x>>y>>z;
        len[x][y]=z;
    }
    bfs();
    if(d[n][m]==0x3f3f3f3f) cout<<-1<<endl;
    else cout<<d[n][m]<<endl;
}
signed main()
{
    solve();
    return 0;
}

J.合唱比赛

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<deque>
#include<set>
#include<queue>
#include<vector>
#include<cstdio>
#define int long long
using namespace std;
void solve()
{
    int n;
    cin>>n;
    vector<int>a;
    int sum=0;
    for(int i=0;i<n;i++){
        int x;
        cin>>x;
        a.push_back(x);
        sum+=x;
    }
    sort(a.begin(),a.end());
    int len=a.size();
    int sum1=sum-a[len-1];
    printf("%.6f ",(double)sum1/(n-1));
    int sum2=sum-a[0];
    printf("%.6f\n",(double)sum2/(n-1));
}
signed main()
{
    solve();
    return 0;
}

K.以撒和隐藏房间

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<deque>
#include<set>
#include<queue>
#include<vector>
#include<cstdio>
#define int long long
using namespace std;
const int N=1010;
char s[N][N];
int n,m;
void solve()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>s[i][j];
        }
    }
    int res=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(s[i][j]!='0') continue;
            int normal=0,boss=0;
            if(i-1>=1){
                if(s[i-1][j]=='1') normal++;
                else if(s[i-1][j]=='2') boss++;
            } 
            if(i+1<=n){
                if(s[i+1][j]=='1') normal++;
                else if(s[i+1][j]=='2') boss++;
            } 
            if(j-1>=1){
                if(s[i][j-1]=='1') normal++;
                else if(s[i][j-1]=='2') boss++;
            } 
            if(j+1<=m){
                if(s[i][j+1]=='1') normal++;
                else if(s[i][j+1]=='2') boss++;
            } 
            if(normal==3&&boss==0) res++;
        }
    }
    if(res){
        puts("YES");
        cout<<res<<endl;
    }
    else puts("NO");
}
signed main()
{
    solve();
    return 0;
}

L.中位数

树状数组+二分

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<deque>
#include<set>
#include<queue>
#include<vector>
#include<cstdio>
#include<map>
#define int long long
#define iosy ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
const int N=1e6+10;
int a[N];
int tr[N];
int n,m;
int lowbit(int x){
    return x & -x;
}
void add(int x,int c){
    for(int i=x;i<=N;i+=lowbit(i)) tr[i]+=c;//注意这里区间范围是1e6
}
int sum(int x){
    int res=0;
    for(int i=x;i;i-=lowbit(i)) res+=tr[i];
    return res;
}
void solve()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        add(a[i],1);
    }
    while(m--){
        int p,x;
        cin>>p>>x;
        add(a[p],-1);
        add(x,1);
        a[p]=x;
  //利用二分,在1到1e6之间查找答案
  //我们要找的是中位数,答案只有一个,所以我们只要一直压缩区间,直到最后找到的l和r相等,sum[l]刚好等于(n+1)/2
        int l=1,r=1e6;    
        while(l<r){
            int mid=(l+r)/2;
            if(sum(mid)>=(n+1)/2) r=mid;
            else l=mid+1;
        }
        cout<<l<<endl;
    }
}
signed main()
{
    iosy;
    solve();
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值