Loading

第十一届山东省大学生程序设计竞赛(正式赛) BCDGH

随便VP了一下大概是四题的样子

B. Build Roads

链接:https://ac.nowcoder.com/acm/contest/15600/B
来源:牛客网

题目描述

In the cat country, there are nnn cities. The cat country king wants to build n−1n-1n−1 roads to connect all the cities. The iii-th city has a construction company with an experience value of aia_iai. To build a road between the iii-th city and the jjj-th city, the two cities' construction companies need to cooperate with each other. However, in the process of building a road, the two construction companies may have conflicts due to poor communication, and it will result in a waste of building materials. Formally, building a road between the iii-th city and the jjj-th city will waste gcd⁡(ai,aj)\gcd(a_i, a_j)gcd(ai,aj) building materials.

Can you help the cat country king choose to build n−1n-1n−1 roads that connect all the cities and minimize the waste of building materials?

To decrease the input size, the king of the cat country gives you a random integer generator and 333 parameters L,R,seedL,R,seedL,R,seed. The following C language code shows how to generate nnn integers a1,a2,…,ana_1, a_2, \dots, a_na1,a2,…,an, and a[i]a[i]a[i] stores the experience value of the construction company of the iii-th city. You can use the code directly in your submissions.

img

输入描述:

The only line contains four integers n,L,R,seedn,L,R,seedn,L,R,seed (2≤n≤2×105,1≤L≤R≤2×105,1≤seed≤1018)(2 \le n \le 2 \times 10^5, 1 \le L \le R \le 2 \times 10^5, 1 \le seed \le 10^{18})(2≤n≤2×105,1≤L≤R≤2×105,1≤seed≤1018).

输出描述:

Print one integer -- the minimum waste of connecting all the cities.

示例1

输入

[复制](javascript:void(0)😉

5 1 200000 123

输出

[复制](javascript:void(0)😉

4

prim打表可以发现规律(L和R不相等输出n - 1,相等输出l * (n - 1)),范围小暴力范围大直接cout。

具体解释是素数间距很小(素数密度分布),只要L到R范围足够大n足够大就很容易出现素数,只要有一个素数在数组里出现的话就可以把这个城市和其他城市连起来形成一棵最小生成树。

#include <bits/stdc++.h>
using namespace std;
int n, L, R, a[200005];
unsigned long long seed;
unsigned long long xorshift64() {
	unsigned long long x = seed;
	x ^= x << 13;
	x ^= x >> 7;
	x ^= x << 17;
	return seed = x;
}
int gen() {
	return xorshift64() % (R - L + 1) + L;
}
int gcd(int a, int b) {
	return b ? gcd(b, a % b) : a;
}
int aa[205][205], d[205], m, ans = 0;
bool v[205];
void prim() {
	memset(d, 0x3f3f3f3f, sizeof(d));
	memset(v, 0, sizeof(v));
	d[1] = 0;
	for(int i = 1; i < n; i++) {
		int x = 0;
		for(int j = 1; j <= n; j++) {
			if(!v[j] && (x == 0 || d[j] < d[x])) x = j;
		}
		v[x] = 1;
		for(int y = 1; y <= n; y++) {
			if(!v[y]) d[y] = min(d[y], aa[x][y]);
		}
	}
}
signed main() {
	scanf("%d%d%d%lld", &n, &L, &R, &seed);
	for(int i = 1; i <= n; i++) {
		a[i] = gen();
	}
	if(n > 100) {
		if(L != R) cout << n - 1;
		else cout << 1ll * L * (n - 1);//别忘记加上1ll
		return 0;
	}
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= n; j++) {
			if(i == j) aa[i][j] = 1;
			else aa[i][j] = gcd(a[i], a[j]);
		}
	}
	prim();
	long long ans = 0;
	for(int i = 2; i <= n; i++) {
		ans += 1ll * d[i];
	}
	cout << ans << endl;
	return 0;
}

C. Cat Virus]

链接:https://ac.nowcoder.com/acm/contest/15600/C
来源:牛客网

题目描述

In the cat country, any cat family can be regarded as a rooted tree. As we all know, a kind of zombie virus hides in all the cats' bodies. Therefore, a cat family may consist of cats and zombies. When a cat is born, it may become a zombie. If a cat becomes a zombie, all of its offspring will also become zombies.

Now given an integer KKK, you should construct a cat family with exactly KKK ways to mark the identities (cat or zombie) of members of this family. Two ways are considered different if and only if there is at least one member that is marked as a cat in one way and marked as a zombie in the other way.

Formally, the vertices in a rooted tree will be marked black or white, and if a vertex is marked black, all the vertices in its subtree should also be marked black. Given a rooted tree, it's easy to calculate the number of possible valid ways to mark the vertices in the tree. Your task is to construct a rooted tree with exactly KKK ways to mark your tree's vertices. Two ways are considered different if and only if there is at least one vertex such that in one way is marked black and marked white in the other way.

输入描述:

The only line contains an integer KKK (2≤K≤2⋅1018)(2 \le K \le 2 \cdot 10^{18})(2≤K≤2⋅1018) -- the number of valid ways to mark the vertices in the tree.

输出描述:

Let's denote the number of vertices of the tree you construct as nnn, and label the vertices from 111 to nnn where vertex 111 is the root. 

The output should contain nnn lines. In the first line, print one integer nnn (1≤n≤105)(1 \le n \le 10^5)(1≤n≤105). In the each of the next n−1n-1n−1 lines, print two integers u,vu,vu,v (1≤u,v≤n,u≠v)(1 \le u, v \le n, u \neq v)(1≤u,v≤n,u=v) describing an edge in your rooted tree.

It is guaranteed that at least one solution exists. If there are several possible valid solutions, you can print any of them.

示例1

输入

[复制](javascript:void(0)😉

2

输出

[复制](javascript:void(0)😉

1

示例2

输入

[复制](javascript:void(0)😉

3

输出

[复制](javascript:void(0)😉

2
1 2

示例3

输入

[复制](javascript:void(0)😉

5

输出

[复制](javascript:void(0)😉

3
1 2
1 3

示例4

输入

[复制](javascript:void(0)😉

6

输出

[复制](javascript:void(0)😉

4
1 2
2 3
2 4

构造,容易发现给一个点x连一棵子树y的话答案数组num[x] = num[y] + 1。同时又注意到\(num[u] = 1 + \prod_{v}(num[v]+1)\),(前面的1是u涂黑导致整棵树变黑的一种情况),而v为一个叶子结点的话\(num[v]+1 = 2\),因此在当前结点下考虑如下构造:

  1. k为奇数,则先剪掉整棵子树变黑的那一种情况的1,然后k就暂时变成了偶数,这样它就有若干个因子2,这时就给当前结点插单个的叶子结点直到k变成奇数。此时若k<=1说明构造完成,否则再给当前结点插一个新的结点然后继续构造。

  2. k为偶数,则先给当前结点插一个子结点,然后把这个子结点作为当前结点,则变成了k为奇数的情况。

    #include<iostream>
    #include <vector>
    #define int long long
    using namespace std;
    int tot = 1;//表示结点编号到哪里了
    long long k;
    struct edge {
    	int u, v;
    };
    vector<edge> ans;
    //k = 11
    signed main() {
    	cin >> k;
    	if(k == 2) {
    		cout << 1 << endl;
    		return 0;
    	}
    	while(k > 0) {
    		if(!(k & 1)) {
    			edge nxt;
    			nxt.u = tot, nxt.v = ++tot;
    			ans.push_back(nxt);
    			k--;
    		} else {
    			long long tmp = k - 1;
    			//tmp是子树的连乘 tmp是偶数 因此肯定有l个因子2
    			int ori_tot = tot;
    			while(tmp % 2 == 0 && tmp > 0) {
    				edge nxt;
    				nxt.u = ori_tot, nxt.v = ++tot;
    				ans.push_back(nxt);
    				tmp /= 2;
    				if(tmp & 1) break;
    			}
    			//tmp--;
    			if(tmp <= 1) break;
    			edge nxt;
    			nxt.u = ori_tot, nxt.v = ++tot;
    			ans.push_back(nxt);
    			k = tmp;
    		}
    	}
    	cout << ans.size() + 1 << endl;
    	for(int i = 0; i < ans.size(); i++) {
    		cout << ans[i].u << " " << ans[i].v << endl;
    	}
    }
    

    D. Dyson Box

链接:https://ac.nowcoder.com/acm/contest/15600/D
来源:牛客网

题目描述

A Dyson Sphere is a hypothetical megastructure that completely encompasses a star and captures a large percentage of its power output. The concept is a thought experiment that attempts to explain how a spacefaring civilization would meet its energy requirements once those requirements exceed what can be generated from the home planet's resources alone. Only a tiny fraction of a star's energy emissions reach the surface of any orbiting planet. Building structures encircling a star would enable a civilization to harvest far more energy.

One day, Moca has another idea for a thought experiment. Assume there is a special box called Dyson Box. The gravitational field in this box is unstable. The direction of the gravity inside the box can not be determined until it is opened.

The inside of the box can be formed as a 222-dimensional grid, while the bottom left corner's coordinate is (0,0)(0, 0)(0,0) and the upper right corner's coordinate is (2⋅105,2⋅105)(2 \cdot 10^5, 2 \cdot 10^5)(2⋅105,2⋅105). There will be nnn events. In the iii-th event, a new cube will appear, whose upper right corner's coordinate is (xi,yi)(x_i, y_i)(xi,yi) and bottom left corner's coordinate is (xi−1,yi−1)(x_i - 1, y_i - 1)(xi−1,yi−1).

There are two directions of gravity in the box, vertical and horizontal. Suppose Moca opens the box after the iii-th event. In that case, she has 12\frac{1}{2}21 probability of seeing the direction of the gravity inside the box is vertical, and the other 12\frac{1}{2}21 probability is horizontal. And then, she will measure the total length of the outline of all the cubes. If the direction of gravity is horizontal, all the cubes inside will move horizontally to the left under its influence. Similarly, vertical gravity will cause all the cubes to move downward.

Moca hates probability, so that she is asking for your help. If you have known the coordinates of all the cubes in chronological order, can you calculate the total length of these two cases after each event?

输入描述:

The first line contains one integer nnn (1≤n≤2⋅105)(1 \le n \le 2 \cdot 10^5)(1≤n≤2⋅105) -- the number of cubes.


Each of the following nnn lines describes a cube with two integers xi,yix_i, y_ixi,yi (1≤xi,yi≤2⋅105)(1 \le x_i, y_i \le 2 \cdot 10^5)(1≤xi,yi≤2⋅105).


It is guaranteed that no two cubes have the same coordinates.

输出描述:

For each of the nnn cubes, print one line containing two integers -- two answers when the the direction of gravity is vertical and horizontal.

示例1

输入

[复制](javascript:void(0)😉

4
1 2
3 2
2 1
4 1

输出

[复制](javascript:void(0)😉

4 4
8 6
8 8
10 8

其实水平和垂直计算方式是一样的。因此以水平为例。开一个数组cntx表示x这个位置的块有多少。因为块落下来以后不区分,因此计算的时候可以认为是新加的块在最上面。

由于是按顺序加入的,因此考虑在原基础上新落下来一个块对于答案的贡献。

  1. 第一个块对于答案的贡献为4。

  2. 位置x的新块落下来后如果当前位置的块的数量比两边多,那么对答案的贡献+2(两个侧面)。

  3. 如果当前列之前没有块,则对于答案的贡献+2(两个底面)。

  4. 位置x的新块落下来后如果当前位置的块的数量同时小于等于两边的数量,那么对答案的贡献-2(两边的列少了两个侧面)。

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n;
struct cube {
	int x, y;
} c[200005];
//水平和垂直的计算方法是一样的
int cntx[200005], cnty[200005];
signed main() {
	memset(cntx, 0, sizeof(cntx));
	memset(cnty, 0, sizeof(cnty));
	cin >> n;
	int prex = 0, prey = 0;
	for(int i = 1; i <= n; i++) {
		cin >> c[i].x >> c[i].y;
		if(i == 1) {
			cout << 4 << " " << 4 << endl;
			cntx[c[i].x]++;
			cnty[c[i].y]++;
			prex = 4;
			prey = 4;
			continue;
		} 
		cntx[c[i].x]++;
		cnty[c[i].y]++;
		//计算多加了这一个以后的贡献 由于落下来以后所有小方块不区分 因此可以把新加的看作落在最上面
		//计算x
		if(c[i].x == 1 && cntx[c[i].x + 1] < cntx[c[i].x] || c[i].x == 2 * 100000 && cntx[c[i].x - 1] < cntx[c[i].x] || cntx[c[i].x - 1] < cntx[c[i].x] && cntx[c[i].x + 1] < cntx[c[i].x]) {
			prex += 2;
		}
		if(cntx[c[i].x] == 1) prex += 2;//这一溜第一个 要加上上下两个底
		if(c[i].x - 1 >= 1 && c[i].x + 1 <= 2 * 100000 && cntx[c[i].x] <= cntx[c[i].x - 1] && cntx[c[i].x] <= cntx[c[i].x + 1]) {
			prex -= 2;
		}
		//计算y
		if(c[i].y == 1 && cnty[c[i].y + 1] < cnty[c[i].y] || c[i].y == 2 * 100000 && cnty[c[i].y - 1] < cnty[c[i].y] || cnty[c[i].y - 1] < cnty[c[i].y] && cnty[c[i].y + 1] < cnty[c[i].y]) {
			prey += 2;
		}
		if(cnty[c[i].y] == 1) prey += 2;
		if(c[i].y - 1 >= 1 && c[i].y + 1 <= 2 * 100000 && cnty[c[i].y] <= cnty[c[i].y - 1] && cnty[c[i].y] <= cnty[c[i].y + 1]) {
			prey -= 2;
		}
		cout << prex << " " << prey << endl;
	}
}
// 5
// 5 5
// 1 1
// 3 3
// 2 2
// 4 4

G.Grade Point Average

链接:https://ac.nowcoder.com/acm/contest/15600/G
来源:牛客网

题目描述

As soon as Moca entered the university last year as a freshman, she was told that the competition is fierce and everyone was desperately trying to improve their grades. As a result, in the last academic term, Moca studied just as hard as she did in high school.

The college will award scholarships based on the average score of the previous academic term. Unfortunately, someone has the same average score as Moca because the average score is calculated rounding down to only 111 decimal places. For example, Ran's average score is 485≈9.6\frac{48}{5} \approx 9.6548≈9.6 and Moca's average score is 293≈9.6\frac{29}{3} \approx 9.6329≈9.6, but apparently Moca's average score is higher.

Can you help Moca calculate her average score rounding down to kkk decimal places?

输入描述:

The first line contains two integers n,kn,kn,k (1≤n,k≤105)(1 \le n, k \le 10^5)(1≤n,k≤105) -- the number of courses and the number of decimal places.


The second line contains nnn integers a1,a2,…,ana_1, a_2, \dots, a_na1,a2,…,an (0≤ai≤100)(0 \le a_i \le 100)(0≤ai≤100) -- the score of each course.

输出描述:

Print one real number in a line that denotes Moca's average score. Notice that your answer must contain kkk decimal places.

示例1

输入

[复制](javascript:void(0)😉

3 10
94 100 99

输出

[复制](javascript:void(0)😉

97.6666666666

在用Java的大整数类和Python的高精各莽了一发后写出了正解...

朴素的想法是每次将sum * 10再除以n,不断提取末位的个位。但这样显然会爆long long。考虑浮点数部分是怎么出来的,当然是余数小于除数造成的。因此每次整体乘10其实只需要余数乘10除以n取个位,然后再将余数模n得到新的余数,进行k次即可。

#include <bits/stdc++.h>
using namespace std;
int n, k, a[100005];
long long sum = 0;
int main() {
	cin >> n >> k;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
		sum += 1ll * a[i];
	}
	cout << sum / n;
	cout << ".";
    long long tmp = sum % n;
	for(int i = 1; i <= k; i++) {
		cout << (tmp * 10 / n) % 10;
		tmp = tmp * 10;
		tmp = tmp % n;
	}
	return 0;
}

链接:https://ac.nowcoder.com/acm/contest/15600/H
来源:牛客网

题目描述

Yuna traveled into the fantasy world. The gods of this world gave her a powerful set of equipment so that she could defeat many fierce monsters. However, she had limited health points and stamina, and she could not kill a large number of monsters.

Adventurer's guild would release nnn monster crusade missions, such as black python and wild wolf. Completing the iii-th mission would consume Yuna hih_ihi health points and sis_isi stamina, and then she would get wiw_iwi gold coins.

In the beginning, Yuna had HHH health points and SSS stamina. When her health points were dropped to less than or equal to 000, she would die. However, when her stamina was dropped to less than 000, she would not give up, and then the overdrawn stamina would be reduced from health points. For example, her health points would be reduced by 333, when her stamina dropped to −3-3−3, and then her stamina would be reset to 000. If her health points can not afford the overdrawn stamina, she would also die.

As a friend of Yuna, can you help her choose some missions to complete to get the maximum number of gold coins? Make sure Yuna does not die, or you will be very sad.

输入描述:

The first line contains three integers n,H,Sn,H,Sn,H,S (1≤n≤1000,1≤H≤300,0≤S≤300)(1 \le n \le 1000, 1 \le H \le 300, 0 \le S \le 300)(1≤n≤1000,1≤H≤300,0≤S≤300).


The next nnn lines describe all the monster crusade missions, where the iii-th line contains three integers hi,si,wih_i, s_i, w_ihi,si,wi (0≤hi,si≤300,1≤wi≤109)(0 \le h_i, s_i \le 300, 1 \le w_i \le 10^9)(0≤hi,si≤300,1≤wi≤109).

输出描述:

Print one integer -- the maximum number of gold coins that Yuna could get.

示例1

输入

[复制](javascript:void(0)😉

2 66 22
1 23 2
66 8 90

输出

[复制](javascript:void(0)😉

2

示例2

输入

[复制](javascript:void(0)😉

4 16 22
1 23 11
5 8 14
2 36 99
15 22 27

输出

[复制](javascript:void(0)😉

27

想了十好几分钟的排序贪心突然发现是挺裸的DP...设dp[i, j]表示在当前状态s为i,h为j的最大收益(由于内存限制省略了一维),转移的时候注意先判s再判h,同时血量一定不能取等,s可以取等。

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, mh, ms;
struct mission {
	int h, s;
	long long w;
} m[1005];
int dp[305][305];
long long ans = 0;
signed main() {
	memset(dp, 0, sizeof(dp));
	cin >> n >> mh >> ms;
	for(int i = 1; i <= n; i++) {
		cin >> m[i].h >> m[i].s >> m[i].w;
	}
	for(int i = 1; i <= n; i++) {
		for(int j = ms; j >= 0; j--) {
			for(int k = mh; k >= 1; k--) {
				dp[j][k] = max(dp[j][k], dp[j][k]);
				if(j >= m[i].s) {
					if(k > m[i].h) {
						dp[j][k] = max(dp[j][k], dp[j - m[i].s][k - m[i].h] + m[i].w);
					}
				} else {
					if(k > (m[i].h + (m[i].s - j))) {
						dp[j][k] = max(dp[j][k], dp[0][k - (m[i].h + (m[i].s - j))] + m[i].w);
					}
				}
				ans = max(ans, dp[j][k]);
			}
		}
	}
	cout << ans;
	return 0;
}

M题死活没看明白啥意思,咕

posted @ 2021-05-13 19:54  脂环  阅读(307)  评论(0编辑  收藏  举报