牛客寒假算法集训1-总结

A

思路:
直接遍历字符串s,判断是否依次出现过dfs和DFS

时间复杂度:
O(∑n)

#include <bits/stdc++.h>

using namespace std;

int t,n;
string a;

int main()
{
    cin>>t;
    while(t--)
    {
        int s1=0,s2=0;
        cin>>n>>a;
        int b=0,c=0;
        for(int i=0;i<n;i++)
        {
            if(a[i]=='D'&&b==0) b++;
            else if(a[i]=='F'&&b==1) b++;
            else if(a[i]=='S'&&b==2) b++;
            
            if(a[i]=='d'&&c==0) c++;
            else if(a[i]=='f'&&c==1) c++;        
            else if(a[i]=='s'&&c==2) c++;
        }
        if(b==3) s1=1;if(c==3) s2=1;
        cout<<s1<<" "<<s2<<endl;
    }
    
    return 0;
}

B

思路:
利用mp1存第一行有火的列,mp2存第二行有火的列。再遍历mp1,用flag1,flag2,flag3,flag4标记左右是否堵住,左右是否有火。分类讨论当中间(2,0)有火时的情况,当中间没有火的情况。

时间复杂度:
O(∑nlogn)

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int t,n;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>t;
    while(t--)
    {
        int res=0;//答案
        //mp1[-3]=1表示(1,-3)有火,mp2[-3]=1表示(2,-3)有火
        unordered_map<int,int>mp1,mp2;
        //记录左边是否堵住,右边是否堵住,左边是否有火,右边是否有火
        bool flag1=0,flag2=0,flag3=0,flag4=0;
        
        //输入
        cin>>n;
        for(int i=0;i<n;i++)
        {
            int a,b;
            cin>>a>>b;
            if(a==1) mp1[b]=1;
            else mp2[b]=1;
        }
        //遍历mp1
        for(auto x : mp1)
        {
            int a=x.first;
            if(a<0)
            {
                flag3=true;//左边有火
                if(mp2[a]==1||mp2[a-1]==1||mp2[a+1]==1) flag1=true;//左边堵住
            }
            else if(a>0)
            {
                flag4=true;//右边有火
                if(mp2[a]==1||mp2[a-1]==1||mp2[a+1]==1) 
                {
                    flag2=true;//右边堵住
                    //cout<<"here"<<endl;
                }
            }
        }
        for(auto x : mp2)
        {
            if(x.second==1)
            {
                int a=x.first;
                if(a<0)
                {
                    flag3=true;//左边有火
                    if(mp1[a]==1||mp1[a-1]==1||mp1[a+1]==1) flag1=true;//左边堵住
                }
                else if(a>0)
                {
                    flag4=true;//右边有火
                    if(mp1[a]==1||mp1[a-1]==1||mp1[a+1]==1) flag2=true;//右边堵住
                }
            }
        }
        if(mp2[0]==1)//中间堵住
        {
            if(flag1==1&&flag2==1) res=0;//左右都堵住
            else if(mp1[-1]==1&&mp1[1]==1) res=0;//鸡相邻左右都有火
            else if(mp1[-1]==1&&flag2==true) res=0;//左边堵住,鸡相邻右边有火
            else if(mp1[1]==1&&flag1==true) res=0;//右边堵住,鸡相邻左边有火
            //左边堵住,右边堵住,鸡相邻左边有火,鸡相邻右边有火,四种情况其中之一
            else if(mp1[-1]==1||mp1[1]==1||flag1==true||flag2==true) res=1;
            else res=2;//其他情况需在鸡相邻左右加火
        }
        else
        {
            if(flag1==true&&flag2==true) res=0;//左右都堵住
            else if(flag1==true&&flag4==true) res=1;//左边堵住,右边有火
            else if(flag2==true&&flag3==true) res=1;//右边堵住,左边有火
            else if(mp1[-1]==1&&mp1[1]==1) res=1;
            else if(mp1[-1]==1||mp1[1]==1) res=2;
            else if(flag1==true)
            {
                res=2;//左边堵住,右边无火
                
            }
            else if(flag2==true) 
            {
                res=2;//右边堵住,左边无火
                //cout<<"this"<<endl;
            }
            else if(flag3==true&&flag4==true) 
            {
                res=2;//左右都没堵住,但都有火
            }
            else res=3;//其他情况,将鸡相邻左右和下方添加火
        }
        cout<<res<<endl;
    }
}

C

思路:
按照办事时间从小到大排序,总不满意度最小。二分插入位置mid,插入后其前面人员不满意度不变,其后人员每人不满意度都加上tc,插队后总不满意度为sm+(n-x)*tc

时间复杂度:
O(nlogn+q)

AC代码:

#include <bits/stdc++.h>

using namespace std;

const int N=1e5+10;
long long q,n,t;
long long a[N],sum[N];
long long m,s;

bool check(long long mid)//二分
{
    if((n-mid)*t<=m) return true;
    else return false;
}

int main()
{
    cin>>n>>q>>t;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++) 
    {
        a[i]+=a[i-1];
        sum[i]=sum[i-1]+a[i];
    }
    while(q--)
    {
        cin>>m;
        int k=n;
        s=n*t+sum[n];
        if(s-sum[n]<=m) cout<<t<<endl;
        else if(t>m) cout<<a[n]+t<<endl;
        else 
        {  
            int l=1,r=n-1;
            while(l<r)
            {
                long long mid=l+r>>1;
                if(check(mid)) r=mid;
                else l=mid+1;
            }
            cout<<a[l]+t<<endl;
        }
    }
    return 0;//审题真的很重要
}

E

思路:
DFS

时间复杂度:
O(∑n+3^m(n+m))

AC代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <functional>
#define x first
#define y second

using namespace std;
typedef pair<int,int>PII;

const int N=20,INF=1e9;

PII q[N];
int backup[N];
int T,n,m;
int a[N];
int x,y,cnt=INF,red;

void dfs(int u)
{
    if(u>m)//m场比赛结束
    {
        int sum=a[1];
        memcpy(backup,a,sizeof a);//建一个临时数组排序
        sort(backup+1,backup+n+1,greater<int>());//降序排序
        for(int i=1;i<=n;i++)
        {
            if(backup[i]==sum) {red=i; break;}//获取排名
        }
        cnt=min(red,cnt);//更新排名
        return;
    }
    
    a[q[u].x]+=3;//1 鸡赢 2鸡输
    dfs(u+1);
    a[q[u].x]-=3;
    
    a[q[u].y]+=3;//2 鸡赢 1鸡输
    dfs(u+1);
    a[q[u].y]-=3;
    
    a[q[u].x]+=1;//两鸡平局
    a[q[u].y]+=1;
    dfs(u+1);
    a[q[u].x]-=1;
    a[q[u].y]-=1;
}

int main()
{
    cin>>T;
    while(T--)
    {
        memset(a,0,sizeof a);//初始化
        memset(q,0,sizeof a);//初始化
        cnt=INF;//初始化无穷大
        
        cin>>n>>m;
        
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=1;i<=m;i++) cin>>q[i].x>>q[i].y;
        dfs(1);//搜索
        cout<<cnt<<endl;
    }
    return 0;
}

G

思路:
首先处理特殊数据,如果bi大于等于ai的话,相当于白送bi元钱,即m+=bi。其余数据按照ai从大到小排序。用sum存储ai及其后优惠卷的bi总和。接下来遍历ai,假设当前能够使用该优惠卷,则接下来所有的比当前ai小的优惠价都能使用,则此时可用总现金m+sum>=ai。即只要满足m+sum>=ai,则可购买的最大食物原价为m+sum。如果当前不满足m+sum>=ai,则当前优惠卷的bi将无法使用,则更新sum=sum-bi。特判如果遍历所有优惠卷后没有优惠卷可以使用,已有现金m即为可购买的最高原价商品。

时间复杂度:
O(∑nlogn)

AC代码:

#include <bits/stdc++.h>
#define x first
#define y second

using namespace std;

const int N=1e5+10;
long long t,n,m,cnt,my;
typedef pair<int ,int> PII;
PII a[N];

int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n>>m;my=m;cnt=m;
        for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].y; 
        sort(a+1,a+1+n);
        for(int i=1;i<=n;)
        {
            int j=i;
            while(j<=n&&a[j].x==a[i].x) my+=a[j].y,j++;
            if(my>=a[i].x) cnt=my;
            i=j;
        }
        cout<<cnt<<endl;
    }
    return 0;
}

M

思路:
起初是A~F,每次向右可以显示下六道题,如果不足六道就显示最后六题。然后从最后六题开始,每次向左可以显示前六题,如果不足六题显示最前面六题,所以如果n是六的倍数,一共有n/6种显示结果,如果n不是6的倍数,从头到尾有n/6+1种显示结果,从尾到头n/6-2种结果(因为首位两者已经被计算过),一共有2*n/6种结果

时间复杂度:
O(t)

AC代码:

#include <bits/stdc++.h>

using namespace std;

long long t,n;

int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n;
        
        if(n%6==0) cout<<n/6<<endl;
        else cout<<n/6*2<<endl;
    }
    return 0;
}
posted @   Eric`  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示