牛客小白月赛2

牛客小白月赛2:

这篇博文的所有代码没有写注释,没有经历写。实在抱歉。文章中有部分题目用C++写的,是因为我拿Java写出来运行超时了,无奈之下才拿C++写的。文章的题目有的不完整,大家可以到牛客网上查看题目。
牛客小白月赛2

Problem A

xxx总是对数字的神秘感感到好奇。这次,他在纸上写下了 k的平方 个从1 到 k的平方 的数字,并把这些数字排成了 k*k 的方阵。他惊奇地发现,这个方阵中每行、每列和两条主对角线上的数字之和都不一样。他想要更多的方阵,但他再写不出来了。于是他㕛跑来找你,请你给他一个边长为 k的满足上述性质的方阵。
输入描述:
输入共一行,一个整数 k,意义同题面描述。
输出描述:
输出共k行,每行k个整数,表示答案方阵。输出任意一种可行方案即可。
**示例**1
输入
3
输出
1 2 3
8 9 4
7 6 5

题解:
1 2 3 13
4 5 6 14
7 8 9 15
或者,使用 random 的随机方法也可以通过此题。
官网给的题解。我没证明过。

#include<iostream>
using namespace std;
int main(){
    int a[1001][1001];
    int n;
    cin>>n;
    int num=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<n;j++){
            a[i][j]=num++;
        }
    }
    for(int i=1;i<=n;i++){
        a[i][n]=num++;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cout<<a[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}

Problem B

这里写图片描述
链接:https://www.nowcoder.com/acm/contest/86/B
来源:牛客网

示例1

输入

3
0 1 0 0 1 1
2.13 -6.89 1.78 1.20 -7.73 0.56
3.473 -4.326 -4.851 -0.819 2.467 -2.729

输出

0.5000000 0.5000000
1.5864392 1.1869738
3.7990750 -3.076672
题解:
计算几何模板题。这里不细讲了。 要注意的是,使用解方程法计算垂足时,需要特判 k 不存在的情况。这次由于出题人疏忽没 有卡掉不特判的解方程法,所以可能有部分不特判的解方程法跑了过去。这样写的同学下次要注 意特判哦。

import java.util.Scanner;
public class Main{
    public static void main(String args[]){
        Scanner sc = new Scanner(System.in);
        int t=sc.nextInt();
        for(int i=0;i<t;i++){
            double px=sc.nextDouble();
            double py=sc.nextDouble();
            double ux=sc.nextDouble();
            double uy=sc.nextDouble();
            double vx=sc.nextDouble();
            double vy=sc.nextDouble();
            double k1=(vy-uy)/(vx-ux);
            double k2=-1/(k1);
            double b1=uy-k1*ux;
            double b2=py-k2*px;
            double x = (b2-b1)/(k1-k2);
            double y = k1*x+b1;
            System.out.println(x+" "+y);
        }
    }
}

Problem C:

这里写图片描述
链接:https://www.nowcoder.com/acm/contest/86/C
来源:牛客网

示例1

输入
3
cstdio
splay
fstream
输出

Qian
Kun
Qian
题解:
打表题。将所有给出的头文件输入程序,回答询问时直接判断即可。

import java.util.Scanner;
import java.util.ArrayList;
import java.util.List;
public class Main{

    public static void main(String args[]){
        Scanner sc = new Scanner(System.in);
        int t=sc.nextInt();
        String s[]={"algorithm","bitset","cctype","cerrno","clocale","cmath","complex","cstdio",
                    "cstdlib","cstring","ctime","deque","exception","fstream","functional","limits","list",
                    "map","iomanip","ios","iosfwd","iostream","istream","ostream","queue","set","sstream",
                    "stack","stdexcept","streambuf","string","utility","vector","cwchar","cwctype"};
        List<String> l=new ArrayList<String>();
        for(int i=0;i<s.length;i++){
            l.add(s[i]);
        }
        for(int i=0;i<t;i++){
            String temp=sc.next();
            if(l.contains(temp)){
                System.out.println("Qian");
            }
            else{
                System.out.println("Kun");
            }
        }
    }
}

Problem D:

这里写图片描述
题解:
判断是否存在一条欧拉路径经过所有点。先判断图是否联通,若不联通一定不可行;之后数 图中度数为奇数的点的个数,当且仅当这样的点的个数为 0 或 2 时存在满足题意的欧拉路径

import java.util.Scanner;

public class Main{
    public static void main(String args[]){
        Scanner sc = new Scanner(System.in);
        int t=sc.nextInt();
        for(int i=0;i<t;i++){
            int n=sc.nextInt();
            int m=sc.nextInt();
            int a[]=new int[n+1];
            int pre[]=new int[n+1];
            for(int j=1;j<a.length;j++){
                a[j]=0;
                pre[j]=j;
            }
            int u=0;
            int v=0;
            for(int j=0;j<m;j++){
                u=sc.nextInt();
                v=sc.nextInt();
                a[u]++;
                a[v]++;
                Link(u,v,pre);
            }
            int flag=0;
            for(int j=1;j<=n;j++){
                if(find(pre,j)!=1){
                    flag=1;
                    break;
                }
            }
            if(flag==1){
                System.out.println("Xun");
                continue;
            }
            int num=0;
            for(int j=1;j<a.length;j++){
                if(a[j]%2!=0){
                    num++;
                }
            }
            if(num==2||num==0){
                System.out.println("Zhen");
            }
            else{
                System.out.println("Xun");
            }
        }

    }
    static void Link(int u,int v,int pre[]){
        int uu=find(pre,u);
        int vv=find(pre,v);
        if(uu>vv){
            pre[uu]=find(pre,vv);
        }
        else{
            pre[vv]=find(pre,uu);
        }
    }
    static int find(int pre[],int x){
        if(pre[x]==x){
            return x;
        }
        else{
            return find(pre,pre[x]);
        }
    }
}

Problem E:

这里写图片描述

题解:
简单的 Nim 博弈。我们知道当且仅当每一堆的石子数的异或和等于 0 时先手没有必胜策略。 那么我们维护一个异或和,每次修改时将其异或上旧数,再异或上新数。因为 a⊕b⊕b = a 。这 样每次的修改和回答都是 O(1) 的。

#include<iostream>
using namespace std;
int main(){
    int n, q;
    cin>>n>>q;
    int a[100001];
    int ans=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        ans=ans^a[i];
    }
    while(q--){
        int t1;
        int t2;
        cin>>t1>>t2;
        ans=ans^a[t1];
        a[t1]=t2;
        ans=ans^a[t1];
        if(ans!=0){
            cout<<"Kan"<<endl;
        }
        else{
            cout<<"Li"<<endl;
        }
    }
}

Problem F:

这里写图片描述
题解:
一个树上博弈问题。可以发现对于一个局势,假设目前操作的人有 k 种方案可以选择,而这 k 种方案全部会使之后的人获胜,那么面对当前这个局势的人必败;反之,若这 k 种方案中存在 至少一种方案使得之后的人必败,那么面对当前局势的人只要选择这些方案中的一个就可以使自 己必胜。所以我们考虑在树上转移必胜/必败态,最后查询根节点的必胜/必败态即可。时间复杂 度 O(n) 。

import java.util.*;
public class Main{
    static List<Integer> l[];
    static boolean b[];
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        int t=sc.nextInt();
        for(int i=0;i<t;i++) {
            int n,r;
            n=sc.nextInt();
            r=sc.nextInt();
            l= new ArrayList[n+1];
            b=new boolean[n+1];
            for(int j=0;j<l.length;j++) {
                l[j]=new ArrayList<Integer>();
            }
            for(int j=0;j<n-1;j++) {
                int t1=sc.nextInt();
                int t2=sc.nextInt();
                l[t1].add(t2);
                l[t2].add(t1);
            }

            if(dfs(r)) {
                System.out.println("Gen");
            }
            else {
                System.out.println("Dui");
            }
        }
    }
    static boolean dfs(int n) {
        b[n]=true;
        for(int i=0;i<l[n].size();i++) {
            if(!b[l[n].get(i)]) {
                boolean bb=dfs(l[n].get(i));
                if(bb==false) {
                    return true;
                }
            }
        }
        return false;
    }

}

Problem G

这里写图片描述
输出
ekstieks
80.00
题解:
将答案串进行比较得出每个人得分,对于同高分者将姓名串按字典序排序。按题意模拟即可

import java.util.Arrays;
import java.util.Scanner;
public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        int n=sc.nextInt();
        double rate=100.0/n;
        int m=sc.nextInt();
        char c[]=new char[n];
        BoyFriend bf[]=new BoyFriend[m];
        String sAnswer=sc.next();
        for(int i=0;i<c.length;i++) {
            c[i]=sAnswer.charAt(i);
        }
        for(int i=0;i<m;i++) {
            String name = sc.next();
            String answer=sc.next();
            double grade=0;
            for(int j=0;j<answer.length();j++) {
                if(c[j]==answer.charAt(j)) {
                    grade+=rate;
                }
            }
            bf[i]=new BoyFriend(name, grade);
        }
        Arrays.sort(bf);
        System.out.println(bf[0].name);
        System.out.printf("%.2f",bf[0].grade);
    }

}
class BoyFriend implements Comparable<BoyFriend>{
    String name;
    double grade;
    public BoyFriend(String name, double grade) {
        this.name = name;
        this.grade = grade;
    }
    @Override
    public int compareTo(BoyFriend o) {
        // TODO Auto-generated method stub
        if(grade<o.grade) {
            return 1;
        }
        else if(grade>o.grade) {
            return -1;
        }
        else {
            return name.compareTo(o.name);
        }
    }

}

Problem H

这里写图片描述
题解:
从 P 点开始 DFS ,存下其他每个点与 P 点的距离。最后找到这些距离中的第 k 小,直接 输出即可。时间复杂度 O(n) 或 O(nlogn) 。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
public class Main {
    static List<Node> l[];
    static int dis[];
    static boolean vis[];
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        int n=sc.nextInt();
        int p=sc.nextInt();
        int k=sc.nextInt();
        l=new ArrayList[n+1];
        vis=new boolean[n+1];
        dis=new int[n+1];

        for(int i=0;i<l.length;i++) {
            l[i]=new ArrayList<Node>();
        }
        dis[p]=0;
        for(int i=0;i<n-1;i++) {
            int t1=sc.nextInt();
            int t2=sc.nextInt();
            int t3=sc.nextInt();
            l[t1].add(new Node(t2,t3));
            l[t2].add(new Node(t1,t3));
        }
        vis[p]=true;
        dfs(p);
        Arrays.sort(dis);
        System.out.println(dis[k+1]);
    }
    static void dfs(int start) {
        for(int i=0;i<l[start].size();i++) {
            if(!vis[l[start].get(i).to]) {
                dis[l[start].get(i).to]=dis[start]+l[start].get(i).dis;
                vis[l[start].get(i).to]=true;
                dfs(l[start].get(i).to);
            }
        }
    }

}
class Node{
    int to;
    int dis;
    public Node(int to, int dis) {
        this.to = to;
        this.dis = dis;
    }
}

Problem I

这里写图片描述

题解:
考虑贪心。对于每一时刻,应当在舞台一,舞台二和不观看电视者三者中选择一个最大值。首 先将每个台的节目按先后顺序排序,然后对于每个状态不变的区间取较优值,答案加上这个较优 值乘以区间长度的乘积就可以了。 这里状态不变表示在这个区间中没有舞台切换节目。这样的话在这一个区间中较优值不变

import java.util.Arrays;
import java.util.Scanner;
public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        int t=sc.nextInt();
        Prog p1[]=new Prog[n];
        Prog p2[]=new Prog[m];
        for(int i=0;i<p1.length;i++) {
            p1[i]=new Prog(sc.nextInt(),sc.nextInt());
        }
        for(int i=0;i<p2.length;i++) {
            p2[i]=new Prog(sc.nextInt(),sc.nextInt());
        }
        Arrays.sort(p1);
        Arrays.sort(p2);
        int index1=0;
        int index2=0;
        long result=0;
        for(int i=0;i<t;i++) {
            if(index1+1<n&&p1[index1+1].s==i) {
                index1++;
            }
            if(index2+1<m&&p2[index2+1].s==i) {
                index2++;
            }
            int t1=p1[index1].v;
            int t2=p2[index2].v;
            t1=Math.max(t1, t2);
            if(t1>0) {
                result+=t1;
            }
        }
        System.out.println(result);
    }

}
class Prog implements Comparable<Prog>{//programer 节目
    int s;
    int v;
    public Prog(int s, int v) {
        super();
        this.s = s;
        this.v = v;
    }

    @Override
    public int compareTo(Prog o) {
        // TODO Auto-generated method stub
        return s-o.s;
    }
}

Problem J

这里写图片描述
题解:
一个简单的构造方法:先放最大的,再放最小的,再放第二大的,然后放第二小的……以此类推。 或者表述为:先将元素从小到大排序,得到 a1,a2,a3,··· ,an ,然后排列得到 an,a1,an−1,a2,an−2,··· 。或者先放最小的,再放最大的…这样的方法也可以。有多种证明方法可以证明这是最优解

import java.util.Arrays;
import java.util.Scanner;
public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        int n=sc.nextInt();
        int a[]=new int[n];
        for(int i=0;i<a.length;i++) {
            a[i]=sc.nextInt();
        }
        Arrays.sort(a);
        int b[]=new int[n];
        int l=0;
        int r=a.length-1;
        for(int i=0;i<a.length;) {
            b[i++]=a[l++];
            if(i==a.length) {
                break;
            }
            b[i++]=a[r--];
        }
        long result=0;
        result=Math.abs(b[0]-b[n-1]);
        for(int i=1;i<b.length;i++) {
            result+=Math.abs(b[i]-b[i-1]);
        }
        System.out.println(result);
    }

}

欢迎指正

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值