校赛题解
A. Bit++
题目链接:https://oj.7326it.club/problem/1047
思路:
定义一个变量初值为0,有加号变量+1,有减号变量-1。输出那个变量。。。
代码:
C/C++:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
while(cin >> n)
{
int ans = 0;
while(n--) {
string s;
cin >> s;
if(s[0] == '+' || s[1] == '+' || s[2] == '+')
ans++;
else
ans--;
}
cout << ans << endl;
}
return 0;
}
java:
public class Main{
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
String[] s=new String[n];
int x=0;
for(int i=0;i<n;i++){
s[i]=sc.next();
if(s[i].equals("X++")){
x++;
}else if(s[i].equals("X--")){
x--;
}else if(s[i].equals("--X")){
--x;
}else if(s[i].equals("++X")){
++x;
}else if(s[i].equals("--X")){
--x;
}
}
System.out.println(x);
}
}
B. 排名规则
题目链接:https://oj.7326it.club/problem/1055
思路:
定义一个结构体里面有两个变量,总分和名字(我这里用的string,也可以用char类型,char类型比较需要用strcmp())。有一种超好用的排序叫快速排序,时间复杂度O(nlog(n)),在C++中只需一句话就可以实现快速排序,但是默认的排序是从小到大排序,你需要从新定义一个排序规则cmp函数。现在这个题让先按总分从大到小排序,如果成绩相同,再按字典序升序排序。那么cmp函数就这样来定义:
bool cmp(Node x, Node y)
{
if(x.sum == y.sum)
return x.s < y.s;
else
return x.sum > y.sum;
}
那么这个题就这样就完了。
不懂的去网上搜快速排序。。
代码:
C/C++:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100+5;
struct Node{
int sum;
string s;
}node[maxn];
bool cmp(Node x, Node y)
{
if(x.sum == y.sum)
return x.s < y.s;
else
return x.sum > y.sum;
}
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i++) {
int a, b, c;
string ch;
cin >> a >> b >> c >> ch;
node[i].sum = a + b + c;
node[i].s = ch;
}
sort(node, node+n, cmp);
for(int i = 0; i < n; i++)
cout << node[i].s << " " << node[i].sum << endl;
return 0;
}
java:
类似于C语言结构体思想的做法,利用类的继承。。
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
Person[] person = new Person[n];
for (int i = 0; i < n; i++) {
int x1 = cin.nextInt();
int x2 = cin.nextInt();
int x3 = cin.nextInt();
person[i] = new Person(x1 + x2 + x3, cin.nextLine().trim());
}
Arrays.sort(person);
for (int i = 0; i < n; i++) {
System.out.println(person[i].name + " " + person[i].score);
}
}
static class Person implements Comparable<Person> {
int score;
String name;
public Person(int score, String name) {
this.score = score;
this.name = name;
}
@Override
public int compareTo(Person o) {
if (score == o.score) return name.compareTo(o.name);
return score > o.score ? -1 : 1;
}
}
}
C. 四个数的和为0
题目链接:http://120.79.201.82/problem/1050
思路:
4层for循环肯定超时。
让你找4个数的和,你可以两个两个的找,然后相加,但是里面会有重复的情况,需要特判一下。可以用结构体来存两个数下标和两个数的和。只需要判下标重不重就ok。
现在把任意两个数的和先求出来。排序一下。现在可以用类似二分的那种方法,l = 0, r = tot-1,然后最左边元素加最右边元素,并且判断有没有重复的,如果等于0直接输出“Yes”结束。如果小于0,说明左边比较小,左边+1。如果大于0,右边+1。如果没有找到输出“No”。
代码:
C/C++:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1005;
long long a[maxn];
struct node{
long long sum;
int i, j;
}data[maxn*maxn];
bool cmp(node x, node y)
{
return x.sum < y.sum;
}
int main()
{
int n;
scanf("%d" ,&n);
int tot = 0;
for(int i = 0; i < n; i++ )
scanf("%lld" ,&a[i]);
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if(i != j) {
data[tot].i = i;
data[tot].j = j;
data[tot++].sum = a[i] + a[j];
}
}
}
sort(data, data+tot, cmp);
int l = 0;
int r = tot-1;
int flag = 0;
while(l < r) {
if(data[l].sum + data[r].sum == 0 && (data[l].j != data[r].i) && (data[l].i != data[l].j) && (data[r].j != data[r].i)) {
printf("Yes\n");
flag = 1;
break;
}
else if(data[l].sum + data[r].sum < 0)
l++;
else if(data[l].sum + data[r].sum > 0)
r--;
else {
l++;
r--;
}
}
if(!flag)
printf("No\n");
return 0;
}
D. Welcome (签到)
题目链接:http://120.79.201.82/problem/1048
思路:
不需要思路,直接干。 (注意数据范围)
int的范围为 -2147483648~2147483647 2e9
long long的范围为 -9223372036854775808~9223372036854775807 9e18
题目说 0<=a,b<=10^9
所以肯定超int范围,所以long long
long long的输入输出为%lld
代码:
C/C++:
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long a, b;
scanf("%lld", &a, &b);
printf("%lld\n", a*b-1);
return 0;
}
java:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
long a=in.nextLong();
long b=in.nextLong();
System.out.println(a*b-1);
}
}
E. WFU (一个不需要任何思考的题)
题目链接:http://120.79.201.82/problem/1049
思路:
直接肝。。。
注意后面空格也需要复制上,两个“\\"输出一个“\”。
代码:
C/C++:
#include <stdio.h>
int main()
{
printf(" _____ _____ _____ \n");
printf(" /\\ \\ /\\ \\ /\\ \\ \n");
printf(" /::\\____\\ /::\\ \\ /::\\____\\ \n");
printf(" /:::/ / /::::\\ \\ /:::/ / \n");
printf(" /:::/ _/___ /::::::\\ \\ /:::/ / \n");
printf(" /:::/ /\\ \\ /:::/\\:::\\ \\ /:::/ / \n");
printf(" /:::/ /::\\____\\ /:::/__\\:::\\ \\ /:::/ / \n");
printf(" /:::/ /:::/ / /::::\\ \\:::\\ \\ /:::/ / \n");
printf(" /:::/ /:::/ _/___ /::::::\\ \\:::\\ \\ /:::/ / _____ \n");
printf(" /:::/___/:::/ /\\ \\ /:::/\\:::\\ \\:::\\ \\ /:::/____/ /\\ \\ \n");
printf("|:::| /:::/ /::\\____\\/:::/ \\:::\\ \\:::\\____\\:::| / /::\\____\\\n");
printf("|:::|__/:::/ /:::/ /\\::/ \\:::\\ \\::/ /:::|____\\ /:::/ /\n");
printf(" \\:::\\/:::/ /:::/ / \\/____/ \\:::\\ \\/____/ \\:::\\ \\ /:::/ / \n");
printf(" \\::::::/ /:::/ / \\:::\\ \\ \\:::\\ \\ /:::/ / \n");
printf(" \\::::/___/:::/ / \\:::\\____\\ \\:::\\ /:::/ / \n");
printf(" \\:::\\__/:::/ / \\::/ / \\:::\\__/:::/ / \n");
printf(" \\::::::::/ / \\/____/ \\::::::::/ / \n");
printf(" \\::::::/ / \\::::::/ / \n");
printf(" \\::::/ / \\::::/ / \n");
printf(" \\::/____/ \\::/____/ \n");
printf(" ~~ ~~ ");
}
java:
public class Main {
public static void main(String[] args) {
String s = " _____ _____ _____ \r\n" +
" /\\ \\ /\\ \\ /\\ \\ \r\n" +
" /::\\____\\ /::\\ \\ /::\\____\\ \r\n" +
" /:::/ / /::::\\ \\ /:::/ / \r\n" +
" /:::/ _/___ /::::::\\ \\ /:::/ / \r\n" +
" /:::/ /\\ \\ /:::/\\:::\\ \\ /:::/ / \r\n" +
" /:::/ /::\\____\\ /:::/__\\:::\\ \\ /:::/ / \r\n" +
" /:::/ /:::/ / /::::\\ \\:::\\ \\ /:::/ / \r\n" +
" /:::/ /:::/ _/___ /::::::\\ \\:::\\ \\ /:::/ / _____ \r\n" +
" /:::/___/:::/ /\\ \\ /:::/\\:::\\ \\:::\\ \\ /:::/____/ /\\ \\ \r\n" +
"|:::| /:::/ /::\\____\\/:::/ \\:::\\ \\:::\\____\\:::| / /::\\____\\\r\n" +
"|:::|__/:::/ /:::/ /\\::/ \\:::\\ \\::/ /:::|____\\ /:::/ /\r\n" +
" \\:::\\/:::/ /:::/ / \\/____/ \\:::\\ \\/____/ \\:::\\ \\ /:::/ / \r\n" +
" \\::::::/ /:::/ / \\:::\\ \\ \\:::\\ \\ /:::/ / \r\n" +
" \\::::/___/:::/ / \\:::\\____\\ \\:::\\ /:::/ / \r\n" +
" \\:::\\__/:::/ / \\::/ / \\:::\\__/:::/ / \r\n" +
" \\::::::::/ / \\/____/ \\::::::::/ / \r\n" +
" \\::::::/ / \\::::::/ / \r\n" +
" \\::::/ / \\::::/ / \r\n" +
" \\::/____/ \\::/____/ \r\n" +
" ~~ ~~ \r\n" +
"";
System.out.println(s);
}
}
F. 完美字符串
题目链接:http://120.79.201.82/problem/1052
思路:
完美度最大也就是,字符串里出现次数最多的字母,给他最大的数26,第二大多的字母,给他25。以此类推。。
不区分大小写,这时候需要另做判断大写还是小写。这里面需要用一个数组来存他们字母出现的次数。字母A用
a[0]存,字母B用a[1]存, 字母C用a[2]存。以此类推。。
然后对a数组由大到小排序。这里我用的快速排序sort()。然后从26a[0]+25a[1]+24[2],只要a[i]等于0就退出循环。
代码:
C/C++:
#include<bits/stdc++.h>
using namespace std;
int a[27];
bool cmp(int x, int y)
{
return x > y;
}
int main()
{
string s;
cin >> s;
int len = s.length();
for(int i = 0; i < len; i++) {
if(s[i] >= 'a' && s[i] <= 'z')
a[s[i] - 'a']++;
else
a[s[i] - 'A']++;
}
sort(a, a+26, cmp);
int sum = 0;
int p = 26;
for(int i = 0; i < 26; i++) {
if(a[i] > 0) {
sum += a[i] * p;
p--;
}
else
break;
}
cout << sum << endl;
return 0;
}
java:
import java.util.Scanner;
public class Main {
static int a[]=new int[27];
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
String s=in.next();
for(int i=0;i<s.length();i++){
if(s.charAt(i)>='a'&&s.charAt(i)<='z')
a[s.charAt(i)-'a']++;
else
a[s.charAt(i)-'A']++;
}
for(int i=0;i<25;i++){
for(int j=i+1;j<26;j++){
if(a[i]<a[j]){
int t=a[i];
a[i]=a[j];
a[j]=t;
}
}
}
int sum=0;
for(int i=0;i<26;i++){
sum+=a[i]*(26-i);
}
System.out.println(sum);
}
}
G. 字符串长度
题目链接:http://120.79.201.82/problem/1051
思路:
先计算字符串的长度,char[]可以通过strlen(),来算长度。我用的string类型输入的。。
如果长度<=10,原样输出。
否则:先输出头字符,然后输出(总长度-2),最后输出尾字符。
代码:
C/C++:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
while(n--) {
string s;
cin >> s;
int len = s.length();
if(len > 10)
cout << s[0] << len-2 << s[len-1] << endl;
else
cout << s << endl;
}
return 0;
}
java:
import java.util.Scanner;
public class Main {
public static void main(String args[]) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
String s;
for (int i = 0; i < n; i++) {
s = in.next();
//大于10 的情况
if (s.length() > 10){
char a = s.charAt(0);
char b = s.charAt(s.length()-1);
System.out.print(a);
System.out.print(s.length()-2);
System.out.println(b);
}
else //小于10的情况
System.out.println(s);
}
}
}
H. 最高的奖励
题目链接:https://oj.7326it.club/problem/1054
思路:
一道好题,出的很妙。。
不知道优先队列的先百度搜一下。。
先利用结构体存储时间q和奖励w两项。这时对时间从小到大排序一下,排序结果如下
时间 奖励
1 30
2 60
3 40
4 20
4 70
4 50
6 10
可以利用优先队列的思想,每次替换之前最小的。所以优先队列的优先级为小的先出队。这里需要判断时间队列的长度和最晚时间的问题,如果队列长度小于最晚时间,这时进队。大于的话如果当前的奖励的比队首大,那么队首出队,让当前进来。
模拟一下样例:
首先先让30进队,
然后当前最晚结束时间为2,现在队的长度为1,满足进队的条件,60进队
然后当前最晚结束时间为3,现在队的长度为2,满足进队条件,40进队
然后当前最晚结束时间为4,现在队的长度为3,满足进队条件,20进队
然后当前最晚结束时间为4,现在队的长度为4,不满足进队条件,当前的奖励为70和队首的奖励为20,所以队首20出队,70进队
然后当前最晚结束时间为4,现在队的长度为4,不满足进队条件,当前的奖励为50和队首的奖励为30,所以队首30出队,50进队
然后当前最晚结束时间为6,现在队的长度为4,满足进队条件,10进队.
结束操作,此时队列中的元素和为60+40+70+50+10=230.
代码:
C/C++:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 50000+10;
struct node{
int q;
int w;
}data[maxn];
bool cmp(node x, node y)
{
return x.q < y.q;
}
int main()
{
int n;
cin >> n;
priority_queue<int , vector<int >, greater<int> > pq;
for(int i = 0; i < n; i++)
cin >> data[i].q >> data[i].w;
sort(data, data+n, cmp);
pq.push(data[0].w);
for(int i = 1; i < n; i++) {
if(data[i].q > pq.size()) {
pq.push(data[i].w);
}
else {
if(data[i].w > pq.top()) {
pq.pop();
pq.push(data[i].w);
}
}
}
long long ans = 0;
while(!pq.empty()) {
ans += pq.top();
pq.pop();
}
cout << ans << endl;
return 0;
}
java:
import java.util.*;
//运用c/c++结构体的思想
//在Java中继承以恶搞Comparable
//然后重写compareTo
public class Main {
public static void main(String[] args) {
PriorityQueue<Integer> points = new PriorityQueue<Integer>();
ArrayList<Point> arrayList = new ArrayList<>();
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
for (int i = 0; i < n; i++) {
arrayList.add(new Point(cin.nextInt(), cin.nextInt()));
}
cin.close();
Collections.sort(arrayList);
long len = 0, ans = 0;
for (Point point : arrayList) {
if (len < point.time) {
len++;
ans += point.weight;
points.add(point.weight);
} else if (len == point.time && point.weight > points.peek()) {
ans += point.weight;
points.add(point.weight);
ans -= points.poll();
}
}
System.out.println(ans);
}
static class Point implements Comparable<Point>{
int time;
int weight;
public Point(int time, int weight) {
this.time = time;
this.weight = weight;
}
@Override
public int compareTo(Point o) {
return time > o.time?1:-1;
}
}
}
I. 小可爱分块
题目链接: http://120.79.201.82/problem/1029
思路:
假设现在n序列为2,4,6,8,k为2,那么他至少需要把前两个位置中的1个置为1,和把后两个位置中的其中1个置位1。相当于每k个需要置1个1。才能保证>=k的字串,gcd=1。
代码:
C/C++:
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long a, b;
cin >> a >> b;
cout << a / b << endl;
return 0;
}
java:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
long n = cin.nextLong();
long k = cin.nextLong();
System.out.println(n / k);
}
}
J. 转圈游戏
题目链接:https://oj.7326it.club/problem/1056
思路:
这是一道规律题,同时还用到了快速幂。不懂快速幂的可以去百度一下。
你可以在纸上模拟一下这个游戏,可以发现n个一循环。
可以发现,每轮一次,x的位置加m,可以推出(x+轮*m)% n,然后通过快速幂求出轮数。
代码:
C/C++:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n, m, k, x;
ll qsm(ll a, ll b)
{
ll ans = 1;
ll t = a;
while(b) {
if(b&1) {
ans = (ans * t) % n;
}
t = (t * t) % n;
b >>= 1;
}
return ans % n;
}
int main()
{
cin >> n >> m >> k >> x;
ll pos = qsm(10, k);
ll start = x;
ll end = (x + pos * m)%n;
cout << end << endl;
return 0;
}
java:
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int m=input.nextInt();
int k=input.nextInt();
int x=input.nextInt();
//快速幂思想 不会的在网上自己理解
int a=k;
int t=10,ans=1;
while(a!=0)
{
if(a%2!=0)
ans=(ans*t)%n;
t=(t*t)%n;
a>>=1;
}
ans=ans%n;
System.out.print((ans*m+x)%n);
}
}
K. 寻找道路
题目链接:https://oj.7326it.club/problem/1053
思路:
已知只有所有出边都直接或间接指向终点的点才可能被选择,所以就建反边,从终点想起点扫,
dfs,bfs均可,在把所有终点不能达到的点打上标记0,这些点均不可被选择,并且在反边图中
这些点所指向的点也不能被选择(因为在正边图中这些点指向标记为0的点)。因此可以删去图
中不符合要求的点,然后跑最短路即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=200000+5;
const int inf=99999999;
int cnt;
//向行星的结构
struct node{
int v,w,Next;
}edge[maxn];
int head[maxn];//顶点
int vis[maxn];//跑bfs的标记
int vis1[maxn];//全局的图标记
int vis2[maxn];//跑最短路时的标记
int dis[maxn];//维护最短路的值
//向行星(链表)存储边
void add(int u,int v){
edge[cnt].v=v;
edge[cnt].w=1;
edge[cnt].Next=head[u];
head[u]=cnt++;
}
//初始化
void init(){
memset(head,-1,sizeof(head));
memset(vis,0.,sizeof(vis));
memset(vis1,0.,sizeof(vis1));
memset(vis2,0.,sizeof(vis2));
for(int i=0;i<=maxn;i++)
dis[i]=inf;
cnt=1;
}
//spfa(据说时最稳点的最短路)跑的最短路
void spfa(int x){
memset(vis,0,sizeof(vis));
queue<int>q;//STL 队列
q.push(x);
vis[x]=1;
dis[x]=0;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=edge[i].Next){
int v=edge[i].v;
if(vis1[v]){
if(dis[v]>dis[u]+edge[i].w){
dis[v]=dis[u]+edge[i].w;
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
}
}
//反向建边后标记能够走过的点标记为1,不能走的标记为0 此处的标记数组为vis1数组;
void bfs(int t){
memset(vis,0,sizeof(vis));
queue<int>q;
q.push(t);
vis[t]=1;
vis1[t]=1;
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=edge[i].Next){
int v=edge[i].v;
if(!vis[v])
{
vis[v]=1;
vis1[v]=1;
q.push(v);
}
}
}
}
int main(){
int n,m;
init();
scanf("%d%d",&n,&m);
while(m--){
int x,y;
scanf("%d%d",&x,&y);
add(y,x);//反向建边;
}
int s,t;
scanf("%d%d",&s,&t);
bfs(t);//bfs搜索删除不满足条件的点;
for(int i=1;i<=n;i++)
vis2[i]=vis1[i];
//更新满足条件的点(像样例2 中的2这个点类似的点)
for(int i=1;i<=n;i++){
if(!vis2[i]){
for(int j=head[i];j!=-1;j=edge[j].Next){
int v=edge[j].v;
if(vis1[v]){
vis1[v]=0;
}
}
}
}
//所有点标记完毕后跑一遍最短路 就可以了;
spfa(t);
if(dis[s]>=inf)
printf("-1\n");
else
printf("%d\n",dis[s]);
return 0;
}