GDUFS 2018信息学院程序设计新手赛(正式赛)Java版题解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Cymbals/article/details/84640305

Problem A: HELLO
Description
《绝地求生》(PUBG) 是一款战术竞技型射击类沙盒游戏 。 该游戏中,玩家需要在游戏地图上收集各种资源,并在不断缩小的安全区域内对抗其他玩家,让自己生存到最后。游戏《绝地求生》除获得G-STAR最高奖项总统奖以及其他五项大奖 ,还打破了7项吉尼斯纪录。小洪是这个游戏的狂热爱好者,就在他今天准备“吃鸡”的时候他的舍友小权突然提醒他今天是新手赛!他果断停止游戏,冲向实验室,输入了今天的比赛地址222.201.101.7,但是他发现登不上网站!于是他向你求救!

Input
输入只有一行,由不超过20个字符组成字符串,字符串仅由数字和字符“.”组成,判断其是否是今天的比赛网址。

Output
如果是输入的字符串是 “222.201.101.7” (不包括双引号),那么输出"Yes",否则输出 “No”

Sample Input
222.201.101.5

Sample Output
No

简单的字符串比较题,但是用“==”比较是不行的,这样比较的是两个字符串对象的引用,需要使用“equals”函数比较。

import java.util.Scanner;
 
public class Main {
    static String pa = "222.201.101.7";
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        String in = reader.next();
        if(in.equals(pa)) {
            System.out.println("Yes");
        } else {
            System.out.println("No");
        }
    }
}

Problem B: ORZ
Description
《英雄联盟》(简称LOL)是由美国拳头游戏(Riot Games)开发、中国大陆地区腾讯游戏代理运营的英雄对战MOBA竞技网游。游戏里拥有数百个个性英雄,并拥有排位系统、符文系统等特色养成系统。《英雄联盟》还致力于推动全球电子竞技的发展,除了联动各赛区发展职业联赛、打造电竞体系之外,每年还会举办“季中冠军赛”“全球总决赛”“All Star全明星赛”三大世界级赛事,获得了亿万玩家的喜爱,形成了自己独有的电子竞技文化。小洪是英雄联盟的狂热爱好者,今天他决定学习三角形打野法。现在给你三条边,小洪可以花费一点法力让某一条边的长度增加1,请问要使得这三条边能组成三角形,最少需要多少法力?

Input
输入只有一行,三个数字A,B,C,分别代表三条边的长度。
所有数字范围为 (1~100)

Output
一个整数,代表最少需要多少法力,才能使得这三条边能组成一个三角形。

Sample Input
样例输入1:
3 4 5

样例输入2:
2 3 5

样例输入3:
100 10 10

Sample Output
样例输出1:
0

样例输出2:
1

样例输出3:
81

三角形两边之和大于第三边,如果最小的两边相加都大于第三边,直接输出0即可,如不符合则计算出差了多少。

import java.util.Arrays;
import java.util.Scanner;
 
public class Main {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        int[] tri = new int[3];
        for (int i = 0; i < 3; i++) {
            tri[i] = reader.nextInt();
        }
        Arrays.sort(tri);
        if(tri[0] + tri[1] > tri[2]) {
            System.out.println(0);
            return;
        }
        System.out.println(tri[2] - (tri[0] + tri[1]) + 1);
    }
}

Problem C: NIGHTMARE
Description
《阴阳师》是由中国网易移动游戏公司自主研发的3D日式和风回合制RPG手游。2016年6月1日11:00,《阴阳师》开放安卓首测 ;同年9月2日,登陆ios平台于App Store首发 ;同年9月9日,阴阳师全平台公测 。游戏中的和风元素是以《源氏物语》的古日本平安时代为背景设计的。游戏剧情以日本平安时代为背景,讲述了阴阳师安倍晴明于人鬼交织的阴阳两界中,探寻自身记忆的故事 。小洪是阴阳师的狂热爱好者,今天他十连抽的时候抽到了3个SSR!于是他决定开个Party庆祝。在party中,有一个大Pizza~小洪要把它平均的分给N个小伙伴(包括他自己),那么小洪最少要切多少刀呢?我们假设 Pizza是圆的,并且不能伤害自己的小伙伴-_-||

Input
输入只有一行,一个数字N,代表Party中有N个小伙伴。
所有数字范围为 (1~100)

Output
要平均分的最少刀数

Sample Input
样例输入1:
1

样例输入2:
3

样例输入3:
4

Sample Output
样例输出1:
0

样例输出2:
3

样例输出3:
2

为什么要说不能切小伙伴呢?
以样例2为例,1块披萨分给3个小伙伴,只需要砍死两个小伙伴即可平均分配,显然比切比萨更优。
但是,披萨只能一刀刀切,小伙伴却可以一刀砍死两个,那么这里是输出1还是2呢?
出于这一层考虑,禁止大家考虑切小伙伴的策略。
(魔鬼的胡说八道)

好吧,只考虑切披萨,那么偶数人只需要切一半人数的刀,奇数人则需要刚好切人数刀,只有一个人时不需要切。

至于为什么是这样,请不明白的同学自己切切切。

import java.util.Scanner;
 
public class Main {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        int in = reader.nextInt();
        if(in == 1) {
            System.out.println(0);
            return;
        }
        if(in % 2 == 0) {
            System.out.println(in / 2);
        }else {
            System.out.println(in);
        }
    }
}

Problem D: GAME
Description
《糖果传奇》是由King开发的一款微策略消除手游,于2014年8月发行。游戏设置了超过500关的关卡,在游戏中,玩家可以通过三个或三个以上的糖果以不同方式的连接消除得分,碰撞开不同的障碍物完成任务。小洪是糖果传奇的狂热爱好者。他和他的女朋友都特别喜欢这个游戏,现在他们相约在某个地方一起玩这个游戏。我们假设他们的家在一个X轴上。小洪的家在 X1=a的位置,他女朋友在X2=b的位置。每个人都可以在X轴上行走任意多次。当一个人移动一次的时候,他的疲劳值会改变,疲劳值改变的规则如下:
第一次移动疲劳值增加1,第二次移动疲劳值增加2,第三次移动疲劳值增加3……举个例子,小洪往右走了一步,再往左走了一步(回到初始位置),再往右走了一步,那么他一共走了三步,那么他的疲劳值为 1+2+3=6.

他们俩人会在某个整点相遇,请你帮他们计算,他们要相遇的最少的疲劳值之和。

Input
输入有两行,第一行1数字 a,代表小洪的初始位置
第二行一个数字b,代表他女朋友的初始位置
所有的数字范围为 (1~1000)

Output
让他们相遇的最少的疲劳值之和。

Sample Input
样例输入1:
3
4

样例输入2:
101
99

样例输入3:
5
10

Sample Output
样例输出1:
1

样例输出2:
2

样例输出3:
9

显然你走一步我走一步是最优的,于是我们模拟这个过程就完事了。
先检查一下输入是不是左小右大,如果不是就交换一下,方便我们左走一下右走一下。

import java.util.Scanner;
  
public class Main {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        int a, b, cnt = 0, step = 1;
        a = reader.nextInt();
        b = reader.nextInt();
        if (a > b) {
            int tmp = b;
            b = a;
            a = tmp;
        }
        for (int i = 1;a != b; i++) {
            cnt += step;
            if (i % 2 != 0) {
                ++a;
            } else {
                --b;
                ++step;
            }
        }
        System.out.println(cnt);
    }
}

Problem E: ROAL
Description
《osu!》是一款基于《押忍!战斗!应援团》、《精英节拍特工》和《太鼓达人》等商业游戏改编的免费同人音乐游戏,由Peppy (Dean Herbert)开发制作。小洪是osu狂热爱好者。但是他今天想打锄大地,在他的世界中。牌是没有花色的。现在给你5张牌(1~13),要你判这五张牌能否组成顺子,葫芦,金刚
顺子:五张牌是连续的,如1 2 3 4 5,5 6 7 8 9,9 10 11 12 13,10 11 12 13 1是顺子,但是11 12 13 1 2和 12 13 1 2 3和13 1 2 3 4 不算顺子。
葫芦:三张带一对。如,1 1 1 2 2,5 5 5 6 6,11 11 11 13 13.
金刚:四张带一个。如1 1 1 1 2,13 13 13 13 1.

Input
输入只有一行,每行5个数字,代表5张牌,数字的范围为(1~13)题目保证数字出现的次数不会超过4次。

Output
如果是顺子输出“shunzi”
如果是葫芦输出“hulu”
如果是金刚输出“jingang”
如果都不是输出“lanpai”

Sample Input
样例输入1:
10 11 12 1 13

样例输入2:
5 5 5 5 4

样例输入3:
5 5 5 4 4

样例输入4:
11 12 13 1 2

Sample Output
样例输出1:
shunzi

样例输出2:
jingang

样例输出3:
hulu

样例输出4:
lanpai

我佛了,这题不用map这些库类去写纯用if真的难写。
为了让诸位能看得懂,我就用if写吧…
没啥好说的这题,判断就完事了。

但是要跟Java的同学说一声抱歉,学校oj的java性能实在是太垃圾了,我这份代码也会超时,这样写是没有问题的,唯一一位用Java过的同学使用了BufferedReader,希望没过的同学去了解一下。

import java.util.Arrays;
import java.util.Scanner;
 
public class Main {
    static int[] in = new int[5];
    public static void main(String[] args) {
         Scanner reader = new Scanner(System.in);
         for (int i = 0; i < 5; i++) {
            in[i] = reader.nextInt();
        }
        Arrays.sort(in);
         
        if(in[0] == 1 && in[1] == 10 && in[2] == 11 && in[3] == 12 && in[4] == 13) {
            System.out.println("shunzi");
            return;
        }
         
        boolean flag = false;
        for (int i = 0; i < 4; i++) {
            if(in[i] + 1 != in[i + 1]) {
                flag = true;
                break;
            }
        }
         
        if(!flag) {
            System.out.println("shunzi");
            return;
        }
         
        if(in[0] == in[1] && in[1] == in[2]) {
            if(in[2] != in[3] && in[3] == in[4]) {
                System.out.println("hulu");
                return;
            }
            if(in[2] == in[3] && in[3] != in[4]) {
                System.out.println("jingang");
                return;
            }
        }
         
        if(in[4] == in[3] && in[3] == in[2]) {
            if(in[2] != in[1] && in[1] == in[0]) {
                System.out.println("hulu");
                return;
            }
            if(in[2] == in[1] && in[1] != in[0]) {
                System.out.println("jingang");
                return;
            }
        }
         
        System.out.println("lanpai");
    }
}

Problem F: OMG
Description
《中国式家长》是一款由墨鱼玩游戏开发的模拟养成游戏,游戏已经上架steam、wegame于2018年9月29日正式发售。
《中国式家长》是一款现实主义的模拟游戏,游戏模拟从出生到高考的整段过程,探讨中国孩子与家长之间的关系。2018年10月,《中国式家长》的游戏在网络上引发热议。该游戏销售刚满一个月,已经在一家知名游戏商城上取得全球周销量排行第2名。小洪是中国式家长的狂热爱好者。今天他决定让他的孩子小洲上清华!已知小洲高考的分数,请你计算一下他某几科科目的分数和!我们假设在游戏的世界中,高考科目有很多,然后小洪会让你查询某个区间的分数和。

Input
输入有多行,第一行两个数字N和Q,代表游戏世界中有N个科目和小洪会问你Q个问题。第二行包括N个数字,由空格隔开,每个数字代表小洲一科的高考分数Ai。
接下来有Q行,每行包括两个数字L和R,代表小洪要你告诉他这N个科目中,从第L个到第R个科目的分数的和
(1<=Ai<=100)
(1<=N<=100000)
(1<=Q<=100000)
(1<=L<=R<=N)

Output
对于每个查询,输出一个数字,代表该次查询的分数和。每个数字占一行。

Sample Input
样例输入1:
5 3
1 2 3 4 5
1 2
2 4
1 5

样例输入2:
5 5
100 99 98 1 2
1 1
2 2
4 5
1 5
3 5

Sample Output
样例输出1:
3
9
15

样例输出2:
100
99
3
300
101

这题很快乐的,现场有很多人来问我为什么过不了。

(我样例都过了交上去又是tle又是wa的怎么回事啊.jpg)

看看题目的数据范围,数组长度十万!查询个数10万!10万个1到10万的的累加不超时才怪。

有些精明的小朋友选择了先求总数,然后根据查询来决定是累加求和还是求出不需要求的部分再减掉,可喜可贺,赞赏这些小朋友!

但是如果我给你10万个3万到7万的,那还是gg。

所以这题需要用到一个简单的小算法,前缀和,前缀和每个位置都是前面所有数跟自己的累加,在区间查询的时候,只需要用r位置减去l - 1位置,即可瞬间求出。

这题没有2018学号开头的做出来,一年的差距2333

import java.util.Scanner;
 
public class Main {
    static int[] num = new int[100005];
 
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        int n = reader.nextInt();
        int q = reader.nextInt();
        for (int i = 1; i <= n; i++) {
            num[i] += reader.nextInt();
            num[i + 1] += num[i];
        }
        
        int l, r;
        while (q-- > 0) {
            l = reader.nextInt();
            r = reader.nextInt();
            System.out.println(num[r] - num[l - 1]);
        }
    }
}

Problem G: CRAWLING
Description
《太吾绘卷》是ConchShip Games研发的一款以神话和武侠为题材的独立游戏。玩家将扮演神秘的“太吾氏传人”。
在《太吾绘卷》的世界中,你除了需要扮演神秘的“太吾氏传人”,还将以不同的处世立场——或善、或恶、或中庸——投身于纷繁复杂的江湖之中。你不仅可以拜访世界各地的武林门派,学习种类繁多的功法绝艺;还可以与人义结金兰,或结下血海深仇;不仅可以兴建自己的村庄,经营各种产业;还可以与自己的挚爱生儿育女,缘定三生;直到你终于面对太吾氏的宿敌,击败相枢剑冢,决定世界的命运!小洪是太吾绘卷的狂热爱好者,同时他也很喜欢研究集合问题,最近他在研究邪恶集合,所谓邪恶集合,就是如果这个集合里不存在的最小的非负整数是X,那么这个集合就是邪恶的。现在小洪手里有一个集合,他想把他变成邪恶集合,每一步小洪可以删掉集合里一个数,或者往集合里添加添加一个数,请问小洪最少需要多少步,才能使得这个集合变成邪恶集合!

Input
输入有两行,第一行两个数字 N,X,代表初始集合的大小 ,和题目中的X
第二行包括N个各不相同的数字,代表集合初始的N个数字
所有的数字范围为 (1~10000)

Output
要把这个集合变成邪恶集合的最少步数

Sample Input
样例输入1:
5 3
0 4 5 6 7

样例输入2:
5 1
1 2 3 4 5

样例输入3:
1 0
0

Sample Output
样例输出1:
2

样例输出2:
2

样例输出3:
1

快乐的循环求最小非负,简单题,没过太可惜了。

import java.util.Scanner;
 
public class Main {
    static boolean[] vis = new boolean[205];
 
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        int n, x, g = 0, cnt = 0;
        n = reader.nextInt();
        x = reader.nextInt();
        for (int i = 0; i < n; i++) {
            vis[reader.nextInt()] = true;
        }
        while (g != x) {
            while (vis[g] && g < x) {
                ++g;
            }
            if (g != x) {
                ++cnt;
                ++g;
            }
        }
        if(vis[x]) {
            ++cnt;
        }
        System.out.println(cnt);
    }
}

Problem H: KINGDOM
Description
《王者荣耀》是由腾讯游戏天美工作室群开发并运行的一款运营在Android、IOS、NS平台上的MOBA类手机游戏,于2015年11月26日在Android、IOS平台上正式公测。小洪是王者荣耀的狂热爱好者,但是他最近玩腻了,决定返璞归真,折纸飞机玩。他还邀请了他的ACM的小伙伴们一起玩耍。已知每张纸能够折S个纸飞机,现在有K个小伙伴,每个小伙伴要折N个纸飞机。但是纸只能一包一包的买,已知每包纸有包含P张纸。现在要把纸分给每一个小伙伴,使得每个小伙伴都有足够的纸去折属于他的N个纸飞机,那么请问,他们最少要买多少包纸?注意,纸是不能共享的喔~

Input
输入只有一行,每行4个数字,用空格隔开,分别为 K,N,S,P,每个数字所代表的的意思见上述题面。
所有数字范围为 (1~10000)

Output
一个数字,代表最少要买多少包纸。

Sample Input
样例输入1:
5 3 2 3

样例输入2:
5 3 100 1

Sample Output
样例输出1:
4

样例输出2:
5

小学数学啊,快乐就完事了。
ceil是向上取整。
听说奇奇哥哥和鸿鸿哥哥出过这题作为作业,好吧,其实这题来自codeforce。

import java.util.Scanner;
 
public class Main {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        int k, n, s, p;
        k = reader.nextInt();
        n = reader.nextInt();
        s = reader.nextInt();
        p = reader.nextInt();
        int cost = (int) Math.ceil(1.0 * n / s);
        int tot = cost * k;
        System.out.println((int)Math.ceil(1.0 * tot / p));
    }
}

Problem I: NECKLACE
Description
Codeforces是一家为计算机编程爱好者提供在线评测系统的俄罗斯网站。该网站由萨拉托夫国立大学的一个团体创立并负责运营。
小洪是Codeforces的狂热爱好者,今天他决定打CF,今天CF的签到题非常简单,他决定让你们来做~幸运的是,小洪已经帮你们翻译好题目了。已知一个字符串,让你求这个字符串的所有不同的非空子串的长度乘以该子串出现的次数的和。以下是具体解释

子串:串中任意个连续的字符组成的子序列称为该串的子串,比如有一个串 ababacab,以下串都是他的子串
ab(出现了三次),a(出现了四次),aba(出现了两次),bab,ababcab(出现了一次)等
不同的子串:比如有一个串 ababcab,以下串都是他不同的子串
ab,a,aba,bab,ababcab,c等
子串的长度:即该子串的字符个数,如aba的长度为3,a的长度为1.

Input
输入只有一行,包括一个只由小写字母组成的字符串
字符串的长度为 (1~1000)

Output
这个字符串的所有不同的非空子串的长度乘以该子串出现的次数的和

Sample Input
样例输入1:
a

样例输入2:
aba

样例输入3:
abab

Sample Output
样例输出1:
1

样例输出2:
10

样例输出3:
20

HINT
对于aba他的所有不同的子串有

a(出现了两次)

b(出现了一次)

ab(出现了一次)

ba(出现了一次)

aba(出现了一次)

所以总的答案为 12+11+21+21+3*1 = 10

对于abab,他的所有不同的子串有

a(出现了两次)

b(出现了两次)

ab(出现了两次)

ba(出现了一次)

aba(出现了一次)

bab(出现了一次)

abab(出现了一次)

所以答案为 12+12 +22+21+31+31+4*1 = 20

聪哥:题目要求的是,一个字符串中,所有不同的子串出现的次数乘以他的长度的和。乍一看很难的样子,实际上我们只需要稍作分析,就会发现其实是一个简单题。我们把不同的子串出现的次数这个限制去掉,改成所有子串出现的次数乘以他的长度的和。那么我们就会发现,每一个子串出现的次数都是1次。所以答案就会变成一个很简单的公式了。我们假设原字符串长度为N,那么答案就是,长度为N的子串有一个,长度为N-2的子串有两个,长度为N-3的子串有三个。。。然后直接计算出和即可。

哈哈哈哈哈但是我是用后缀自动机过的啊哈哈哈好快乐啊不要阻止我。

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		 Scanner reader = new Scanner(System.in);
		 String in = reader.next();
		 int sum = 0;
		 for (int i = 0; i < in.length(); i++) {
			sum += i * (in.length() - i + 1);
		}
		 System.out.println(sum);
	}
}

然后给你们感受一下后缀自动机的代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1005;
char s[maxn];
 
struct Sam {
    int next[maxn << 1][26];
    int link[maxn << 1], step[maxn << 1];
    int endpos[maxn << 1];
    int a[maxn], b[maxn << 1];
    int sz, last, root;
 
    void init() {
        //如多次建立自动机,加入memset操作
        root = sz = last = 1;
    }
 
    void add(int c) {
        int p = last;
        int np = ++sz;
        last = np;
 
        endpos[np] = 1;
        step[np] = step[p] + 1;
        while(!next[p][c] && p) {
            next[p][c] = np;
            p = link[p];
        }
 
        if(p == 0) {
            link[np] = root;
        } else {
            int q = next[p][c];
            if(step[p] + 1 == step[q]) {
                link[np] = q;
            } else {
                int nq = ++sz;
                memcpy(next[nq], next[q], sizeof(next[q]));
                step[nq] = step[p] + 1;
                link[nq] = link[q];
                link[q] = link[np] = nq;
                while(next[p][c] == q && p) {
                    next[p][c] = nq;
                    p = link[p];
                }
            }
        }
    }
 
    void build() {
        init();
        for(int i = 0; s[i]; i++) {
            add(s[i] - 'a');
        }
        for(int i = 1; i <= sz; i++) {
            a[step[i]]++;
        }
        for(int i = 1; i <= step[last]; i++) {
            a[i] += a[i - 1];
        }
        for(int i = 1; i <= sz; i++) {
            b[a[step[i]]--] = i;
        }
        for(int i = sz; i > 1; i--) {
            int e = b[i];
            endpos[link[e]] += endpos[e];
        }
    }
 
    void solve() {
        build();
        int ans = 0;
        for(int i = 1; i <= sz; i++) {
            ans += ((step[link[i]] + 1) + step[i]) * (step[i] - step[link[i]]) / 2 * endpos[i];
        }
        printf("%d\n", ans);
    }
 
} sam;
 
int main() {
    scanf("%s", s);
    sam.solve();
    return 0;
}

真长,好处是根本不需要动脑子啊23333,大力ac就完事了。

Problem J: BECAUSE
Description
CTF(Capture The Flag)中文一般译作夺旗赛,在网络安全领域中指的是网络安全技术人员之间进行技术竞技的一种比赛形式。CTF起源于1996年DEFCON全球黑客大会,以代替之前黑客们通过互相发起真实攻击进行技术比拼的方式。发展至今,已经成为全球范围网络安全圈流行的竞赛形式,2013年全球举办了超过五十场国际性CTF赛事。小洪是ACM的狂热爱好者,但是他也业余打打CTF,CTF涉及密码学,在密码学中素数是非常重要的一个东西,今天小洪在打CTF的时候,遇到了一个非常有意思的题目,他决定用ACM的方法去解决它,题目大意是这样的,给你一个正整数N,要你求出所有满足方程 1/X + 1/Y = 1/N 的正整数解的个数,即X>0,Y>0的解的个数。小洪已经解出了这道题目,他决定考考你,看看你是否也能解出来~

Input
输入有包括一行,一个正整数N
所有的数字范围为 (1<=N<=1000000000)(1后面9个0)

Output
满足方程 1/X + 1/Y = 1/N 的正整数解的个数,其中X<=Y

Sample Input
样例输入1:
1

样例输入2:
3

样例输入3:
20180101

样例输入4:
1000000000

Sample Output
样例输出1:
1

样例输出2:
2

样例输出3:
5

样例输出4:
181

聪哥:这实际上是一道数学题,直接百度1/X + 1/Y = 1/N 即可找到详细题解。我们最后可以把公式化简为 N^2 = (N - X) * (N - Y) 所以答案就是求N^2的约数组合数。

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		 Scanner reader = new Scanner(System.in);
		 long n = reader.nextLong();
		 n *= n;
		 
		 long sum = 1;
		 for (long i = 2; i * i <= n; i++) {
			int check = 0;
			if(n % i == 0) {
				check = 1;
				n /= i;
				while (n % i == 0) {
					check++;
					n /= i;
				}
			}
			if(check != 0) {
				sum = sum * (check + 1);
			}
		}
		 
		if(n != 1) {
			sum = sum * 2;
		}
		
		System.out.println((sum - 1) / 2 + 1);
	}
}

猜你喜欢

转载自blog.csdn.net/Cymbals/article/details/84640305