牛客小白月赛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);
}
}
欢迎指正