潍坊学院第三届程序设计竞赛题解

校赛题解

A. Bit++

题目链接:https://oj.7326it.club/problem/1047
思路:

定义一个变量初值为0,有加号变量+1,有减号变量-1。输出那个变量。。。

代码:

C/C++:

#include
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
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
#include
#include
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
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 

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
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
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
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, greater > 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
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个一循环。

1544346217400

可以发现,每轮一次,x的位置加m,可以推出(x+轮*m)% n,然后通过快速幂求出轮数。

代码:

C/C++:

#include
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
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));
    queueq;//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));
    queueq;
    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;
}

你可能感兴趣的:(套题,校赛)