• 牛客小白月赛#59(A~F)


    牛客小白月赛#59

    A.我会开摆

    • 题意

      • 给定n=4的方阵,问是否存在n=2的方阵中四个格子全是一个字符的情况
    • 题解

      • 直接枚举所有点当n=2方阵的左上角,看是否符合题目要求
      • 注意:检查n=2的方阵时,要先排除某点为左上角没有n=2方阵情况
    • 代码

    #include 
    
    using namespace std;
    char a[4][4];
    
    bool check(int x,int y) {//检查以该点为左上角的,n=2的方阵是否符合要求
        char c=a[x][y];
        for(int i=x;i<x+2;i++)
            for(int j=y;j<y+2;j++)
                if(i<4 && j<4 && a[i][j]!=c) return 0;
                
        if(x<3 && y<3) return 1;
        return 0;
    }
    
    bool solve() {
        for(int i=0;i<4;i++) 
            for(int j=0;j<4;j++)
                cin>>a[i][j];
        
        for(int i=0;i<4;i++)//枚举所有点
            for(int j=0;j<4;j++)
                if(check(i,j)) return 1;
                
        return 0;
    }
    
    int main() {
        int t; cin>>t;
        while(t--) cout<<(solve() ? "Yes":"No")<<'\n';
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    B.走廊的灯

    • 题意

      • 路上有n盏灯,0代表灭的,1代表亮的,2代表闪烁,可以看成灭的也可以看成亮的
      • 问最长的状态一样的连续的灯的数量为多少
    • 题解

      • 双指针O(n);每次找到12连续段或者02连续段
      • 暴力O(n*n);数据比较水,不需要双指针。只要枚举以每一个点为起点往后找状态相同的灯,记录最大值即可
      • 注意(代码实现为找同一状态的灯要注意这条,如果遍历时代码实现只看不符合要求的那就不需要看这条):如果2开头,参照的灯的状态为,从左往右第一个不为2的灯的状态
    • 代码

    双指针

    #include 
    #include 
    
    using namespace std;
    
    void solve() {
        int n; cin>>n;
        string s; cin>>s;
        
        int res=1;
        for(int i=0;i<n;i++) {//统计02连续段,因为02段是被1隔开,所以只要不是1就行
            if(s[i]!='1') {
                int j=i;
                while(j<n && s[j]!='1') j++;
                res=max(res,j-i);
                j--; i=j;
            }
        }
        for(int i=0;i<n;i++) {//统计12连续段,同理
            if(s[i]!='0') {
                int j=i;
                while(j<n && s[j]!='0') j++;
                res=max(res,j-i);
                j--; i=j;
            }
        }
        
        cout<<res<<'\n';
    }
    
    int main() {
        int t; cin>>t;
        while(t--) solve();
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    暴力

    #include 
    #include 
    #include 
    
    using namespace std;
    
    void solve() {
        int n; cin>>n;
        string s; cin>>s;
        
        int res=1;
        for(int i=0;i<n;i++) {
            int j=i;
            while(j<n && s[j]=='2') j++;//找到第一个不为2的灯,以它作为参照状态
            char c=s[j];
            while(j<n && (s[j]=='2' || s[j]==c)) j++;//找后面连续的灯
            res=max(res,j-i);//更新答案
        }
        cout<<res<<'\n';
    }
    
    int main() {
        int t; cin>>t;
        while(t--) solve();
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    C.输出练习

    • 题意

      • 从小到大输出区间[l,r]中,k的非负整数次方的值
      • l,r,k范围 [0,2^63)
    • 题解

      • 除去特例的0,1;当k=2时,l=0,r=2^63-1,会有最多个输出,也才64个。所以直接暴力即可
      • 注意特判。k=1时,直接输出1即可,否则暴力和会炸;k=0时,0^0=1,但是0^1=0,0^2=0,即如果区间符合要求,那么k=0会有两个输出。麻麻麻这里WA麻了,好无语
      • 注意数据范围,while(res<=r)这样写会爆long long,应该写成while(res<=r/k) ,又WA好几发,烦死了
    • 代码

    #include 
    #include 
    #include 
    
    using namespace std;
    typedef long long ULL;
    
    void solve() {
        ULL l,r,k;
        cin>>l>>r>>k;
        ULL res=1,cnt=0; 
        if(k==0 && l<=0 && r>=0) cout<<0<<' ',cnt++;//特判
        if(l<=1 && r>=1) cout<<1<<' ',cnt++;
        
        while(k&&k!=1 && res<=r/k) {//数据范围,这样写防止爆long long
            res*=k;
            if(res>=l && res<=r) cout<<res<<' ',cnt++;
        }
        if(cnt==0) cout<<"None.";
        cout<<'\n';
    }
    
    int main() {
        int t; cin>>t;
        while(t--) solve();
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    D.国际象棋

    • 题意

      • 竖直放置的n*m的棋盘,每次选一列放一枚棋子,重力原因棋子落到最下面
      • 对于第i个放置的棋子,i为奇数时,其所放的颜色为黑色,偶数为白色棋子
      • k子连珠定义为:横竖撇捺四个方向存在某个方向有k个相同颜色棋子
      • 一共放t颗棋子,若出现k子连珠则游戏结束,保证有解,问游戏结束时放置了多少棋子
    • 题解

      • 模拟题。

        需要维护的变量:
        棋盘的状态 -> g[n][m]=1/2,来表示棋盘及棋子的状态
        当前列放棋子落在第几行 -> h[i]表示第i列的高度(行数)
        
        需要维护的操作:
        检验当前有无k子连珠 -> check(x,y),以(x,y)为中心去检验四种方向,每种方向正负两个方向去记录连续的相同颜色的棋子数量,数量大于等于k即符合要求
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
    • 代码

    #include 
    
    using namespace std;
    const int N=1005;
    
    int n,m,k,t;
    int g[N][N],h[N];
    int dx[4]={1,0,1,-1},dy[4]={0,-1,-1,-1};//单位向量的定义为横竖撇捺四个方向
    
    
    bool check(int x,int y) {//检验以(x,y)为中心是否存在k子连珠
        for(int d=0;d<=3;d++) {//横竖撇捺四种方向检查
            int cnt=0;//此方向连续的相同颜色棋子数量
            int dxx=dx[d],dyy=dy[d];//偏移量
            int tx=x,ty=y;
          //不越界且连续颜色相同,正方向有多少个
            while(1<=tx&&tx<=n&&1<=ty&&ty<=m && g[tx][ty]==g[x][y]) {
                cnt++; tx+=dxx; ty+=dyy;
            }
            
          //不越界且连续颜色相同,负方向有多少个
            tx=x,ty=y;
            while(1<=tx&&tx<=n&&1<=ty&&ty<=m && g[tx][ty]==g[x][y]) {
                cnt++; tx-=dxx; ty-=dyy;
            }
            cnt--;//多记录了(x,y)自身,去除
            if(cnt>=k) return 1;
        }
        return 0;
    }
    
    int main() {
        cin>>n>>m>>k>>t;
        for(int i=1;i<=t;i++) {//注意是t个棋子
            int x; cin>>x;
            h[x]++;//选择该列,该列的高度增加;注意题目的棋盘是从1开始的
            g[h[x]][x]=((i&1) ? 2:1);//black:2;注意颜色是由输入顺序定义的
            
            if(check(h[x],x)) {cout<<i<<'\n'; return 0;}//有答案输出
        }
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    E.弹珠碰撞

    • 题意

      • 长度为n的线段上有m个弹珠,给定每个弹珠的方向左/右,及坐标
      • 弹珠每秒走一个单位,发生碰撞会停滞一秒,且两珠方向互换,多次碰撞停滞时间叠加
      • 当弹珠走到0,或者n+1认为掉落
      • 问线段上最后掉落的弹珠掉出所花的时间
    • 题解

      • 碰撞转向直接看成穿过就好了,因为弹珠之间没有区别
      • 以某个向左走于位置i的弹珠为例,没有碰撞时时间为i-0,有碰撞需要记录在i左边且方向向右的弹珠数r,时间为i-0+r,从左往右边遍历遍记录答案和数量即可。某个向右走于位置i的弹珠,n+1-i+l,注意这里是逆序遍历。
    • 代码

    #include 
    
    using namespace std;
    const int N=1e6+10;
    
    int n,m,d[N],p[N],seg[N];
    
    int main() {
        cin>>n>>m;
        for(int i=1;i<=m;i++) cin>>d[i];
        for(int i=1;i<=m;i++) cin>>p[i],seg[p[i]]=d[i]+1;
        
        int l=0,r=0,ans=0;
        for(int i=1;i<=n;i++) {
            if(seg[i]==0) continue;
            if(seg[i]==1) ans=max(ans,i-0+r);
            else r++;
        }
        for(int i=n;i>=1;i--) {
            if(seg[i]==0) continue;
            if(seg[i]==2) ans=max(ans,n+1-i+l);
            else l++;
        }
        
        cout<<ans<<'\n';
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    F.困难卷积

    • 题意

      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BcmuODbM-1666978509437)(/Users/chenyanling/Library/Application Support/typora-user-images/image-20221029002156595.png)]
    • 题解

      • trick题。如果我们直接暴力枚举两个数组,复杂度为O(n^2)炸了
      • 观察数据范围特征,数组的和范围在1e7以内,那么考虑与种类数有关,因为贪心构造一个数种类多的数组为0 1 … x,等差数列求和得到x=sqrt(2e7),即数组中最多有sqrt(2e7)种数,此时遍历的复杂度已经降低了,所以开始考虑如何计算答案
      • 以同种类数分别分组a,b后,我们可以得到数num及其出现的次数cnt。那么对于某一组别a1和某一组别b1对于答案的贡献为(a1.cnt * b1.cnt * floor(sqrt(差)),那么只需要枚举a分组和b分组,时间复杂度为O(sqrt(2e7)^2)=O(2e7)
    • 代码

    #include 
    #include 
    #include 
    
    using namespace std;
    map<int,int> ha,hb;
    
    int sqt(int x,int y) {
        return floor(sqrt(abs(x-y)) + 1e-6);//下取整如果是整数计算,加一点精度即可,否则答案不正确
    }
    
    int main() {
        int n; cin>>n;
        for(int i=0;i<n;i++) {
            int x; cin>>x;
            ha[x]++;
        }
        for(int i=0;i<n;i++) {
            int x; cin>>x;
            hb[x]++;
        }
        
        long long res=0;
        for(auto u:ha) 
            for(auto v:hb)
                res+=1ll*u.second*v.second*sqt(u.first,v.first);
        cout<<res<<'\n';
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
  • 相关阅读:
    Java泛型中的 “?super T“ 与 “?extends T“ 有何不同
    C++多态(个人笔记)
    关于数据库分页优化--(oracle, mysql)
    [C/C++] 数据结构 LeetCode:用队列实现栈
    html5视频画质清晰度切换和倍速播放切换代码参考
    Neutron — DHCP Agent 实现原理
    差分进化算法解析:Scala实现详细指南及其在优化问题中的应用
    数据库之MVCC
    基于JavaWeb+SSM+微信小程序基金优选系统的设计和实现
    基于inquirer封装一个控制台文件选择器
  • 原文地址:https://blog.csdn.net/m0_49843646/article/details/127582135