[Codeforces Round #513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2) ](A~E)

A:

题目大意:给你一个数字串,每个数字只可以用一次,求最多可以组成多少个电话号码(可以相同),电话号码第一个数字为$8$,且长度为$11$

题解:限制为$8$的个数和总长度,直接求

卡点:

C++ Code:

#include <cstdio>
#include <algorithm>
#define maxn 1000
inline int min(int a, int b) {return a < b ? a : b;}
inline int max(int a, int b) {return a > b ? a : b;}
int Tim, n, _8;
char s[maxn];
int main() {
	scanf("%d", &n);
	scanf("%s", s + 1);
	for (int i = 1; i <= n; i++) if (s[i] == ‘8‘) _8++;
	printf("%d\n", min(_8, n / 11));
	return 0;
}

  

B:

题目大意:给你一个数$x$,求两个数$a,b$,使得$a+b=n$,且价值和最大,$a$的价值定义为它各个数位上的数字和

题解:$a$尽可能多分$9$,$b$为$x-a$

卡点:

C++ Code:

#include <cstdio>
#include <algorithm>
inline int min(int a, int b) {return a < b ? a : b;}
inline int max(int a, int b) {return a > b ? a : b;}
long long n, a, b, len;
long long ans;
inline int count(long long a) {
	int ans = 0;
	while (a) {
		ans += a % 10;
		a /= 10;
	}
	return ans;
}
int main() {
	scanf("%I64d", &n);
	long long nn = n;
	while (nn) {
		len++;
		nn /= 10;
	}
	ans = (len - 1) * 9;
	for (int i = 1; i < len; i++) a = a * 10 + 9;
	ans += count(n - a);
	printf("%I64d\n", ans);
	return 0;
}

  

C:

题目大意:给定$a_1,a_2,\dots,a_n$和$b_1,b_2,\dots,b_m$。$c_{i,j}=a_ib_j$。

给定$x$,求四个数$x_1,y_1,x_2,y_2$满足:

$\sum_{i=x_1}^{x_2}\sum_{j=y_1}^{y_2}c_{i,j}\leqslant x$。

对于每个满足条件的四元组$(x_1,y_1,x_2,y_2)$,定义其价值为$(x_2-x_1+1)\times(y_2-y_1+1)$,求最大价值。

题解:
$$
\sum_{i=x_1}^{x_2}\sum_{j=y_1}^{y2}c_{i,j}=\sum_{i=x_1}^{x_2}\sum_{j=y_1}^{y2}a_ib_j=(\sum_{i=x_1}^{x_2}a_i)(\sum_{j=y_1}^{y_2}b_j)
$$

记录下每个$x_2-x_1+1$对应最小的$\sum_{i=x_1}^{x_2}a_i$,每个$y_2-y_1+1$对应最小的$\sum_{j=y_1}^{y_2}b_j$,枚举,找最大的即可。

卡点:

C++ Code:

#include <cstdio>
#include <algorithm>
#define maxn 2010
const long long inf = 0x3f3f3f3f3f3f3f3f;
inline long long min(long long a, long long b) {return a < b ? a : b;}
inline long long max(long long a, long long b) {return a > b ? a : b;}
int a[maxn], b[maxn];
long long sa[maxn], sb[maxn], ans, x;
long long A[maxn], B[maxn];
int n, m;
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) scanf("%d", a + i), sa[i] = sa[i - 1] + a[i];
	for (int i = 1; i <= m; i++) scanf("%d", b + i), sb[i] = sb[i - 1] + b[i];
	scanf("%I64d", &x);
	for (int i = 1; i <= n; i++) {
		A[i] = inf;
		for (int j = 1; j <= n - i + 1; j++) {
			A[i] = min(sa[i + j - 1] - sa[j - 1], A[i]);
		}
//		printf("A[%d] : %lld\n", i, A[i]);
	}
	for (int i = 1; i <= m; i++) {
		B[i] = inf;
		for (int j = 1; j <= m - i + 1; j++) {
			B[i] = min(sb[i + j - 1] - sb[j - 1], B[i]);
		}
//		printf("A[%d] : %lld\n", i, B[i]);
	}
	ans = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (A[i] * B[j] <= x) ans = max(ans, i * j);
		}
	}
	printf("%I64d\n", ans);
	return 0;
}

  

D:

题目大意:有$n$个人,坐成若干圈(每人面对圈中间)。第$i$个人左边要有$l_i$个空位,右边要有$r_i$个空位。问至少要多少个座位。

题解:考虑把$l_i$和$r_i$分别看成一个点,则原题变为一张二分图。要求找到一个匹配,每条边的价值为$\max(l_x,r_y)+1$,使得价值最小。

也就是要求“浪费”最少,即按$l$和$r$分别排序,最小连最小,次小连次小……

卡点:前两次没猜中结论。。。

C++ Code:

#include <cstdio>
#include <algorithm>
#define maxn 100010
inline int min(int a, int b) {return a < b ? a : b;}
inline int max(int a, int b) {return a > b ? a : b;}
int n;
long long l[maxn], r[maxn], ans, tmpl, tmpr;
int rnkl[maxn], rnkr[maxn], totl, totr;
bool vl[maxn], vr[maxn];
inline bool cmpl(int a, int b) {return l[a] < l[b];}
inline bool cmpr(int a, int b) {return r[a] < r[b];}
long long sum;
int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) scanf("%I64d%I64d", l + i, r + i);
	std::sort(l + 1, l + n + 1);
	std::sort(r + 1, r + n + 1);
	for (int i = 1; i <= n; i++) ans += max(l[i], r[i]);
	printf("%I64d\n", ans + n);
	return 0;
}

  

E:

题目大意:一棵树。可以在任意两个在原树中距离为$2$的点之间连一条边。求所有点对间最短路的和。

题解:

$$
\begin{align*}
ans&=\sum\limits_{i=1}^{n-1}\sum\limits_{j=i+1}^n\left\lceil\dfrac{dis_{i,j}}{2}\right\rceil\\
&=\dfrac{\sum\limits_{i=1}^{n-1}\sum\limits_{j=i+1}^ndis_{i,j}+奇数的路径数目}{2}\\
\end{align*}\\
$$
易证,求出来的一定是整数

卡点:没开$long\;long$,被$FST$了

C++ Code:

#include <cstdio>
#include <algorithm>
#define maxn 200010
inline int min(int a, int b) {return a < b ? a : b;}
inline int max(int a, int b) {return a > b ? a : b;}
int n;
int head[maxn], cnt = 1;
struct Edge {
	int to, nxt;
} e[maxn << 1];
inline void add(int a, int b) {
	e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
//	e[++cnt] = (Edge) {a, head[b]}; head[b] = cnt;
}
long long ans, ansji;
int fa[maxn];
long long uji[maxn], uou[maxn], dji[maxn], dou[maxn], sz[maxn];
void dfs1(int u) {
	sz[u] = 1;
	dou[u] = 1;
	for (int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if (v != fa[u]) {
			fa[v] = u;
			dfs1(v);
			ans += 1ll * sz[v] * (n - sz[v]);
			sz[u] += sz[v];
			ansji += dji[v] * dji[u] + dou[u] * dou[v];
			dou[u] += dji[v];
			dji[u] += dou[v];
		}
	}
}
int main() {
	scanf("%d", &n);
	for (int i = 1, a, b; i < n; i++) {
		scanf("%d%d", &a, &b);
		add(a, b);
		add(b, a);
	}
	dfs1(1);
	printf("%I64d\n", (ans + ansji >> 1ll));
	return 0;
}

  

原文地址:https://www.cnblogs.com/Memory-of-winter/p/9744854.html

时间: 2024-11-05 21:43:15

[Codeforces Round #513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2) ](A~E)的相关文章

Codeforces Round #513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2)

A.Phone Numbers 题意:给你n个数字,每个数字最多只能用一次,问你最多能组成以8开头的11位电话号码有多少个 思路:模拟即可,注意char数组读入是从0下标开始的(在这里被hack了...) 1 #include<bits/stdc++.h> 2 int main() 3 { 4 int n,num=0,ans=0; 5 char c[105]; 6 scanf("%d%s",&n,c); 7 for(int i=0;i<n;i++)if(c[i

Codeforces Round #513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2) C. Maximum Subrectangle

昨天做的,今天才想起来,要写个博客,记一下这种矩阵题怎么做. 首先我没有意识到,每个方向上累和,得到两个累和数组,它们的子序列之积,就是子序列对应的矩形区域范围内所有数字之和,说起来有点抽象,但是举个栗子吧, 就像用例里面的这张提示图,横坐标我选子列2,3,则和为5,纵坐标我选子列1,2,则和为3.那么3和5,乘积为15,而把矩阵中对应区域的和相加,也是15,.则这个问题就容易了:只需要枚举一维数组就可以了.但是,如果枚举一维数组,那岂不是要做一个四重循环?其实不然. 题目要我们获得一个不大于限

Codeforces Round #513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2) C D

C - Maximum Subrectangle 因为是两个数组相乘的到的 矩阵所以  a(i ->j)*b(x->y) 的面积 就是   a(i ->j) 的和乘与b(x->y)的和 所以我们枚举 a 序列 从1-n的长度和  B序列同理 然后 枚举两个序列和相乘 找一个最大即可 #include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define LL long long #defin

Codeforces Round #513 游记

Codeforces Round #513 游记 A - Phone Numbers 题目大意: 电话号码是8开头的\(1\)位数字.告诉你\(n(n\le100)\)个数字,每个数字至多使用一次.问最多能凑出多少个电话号码. 思路: 统计8出现的次数,如果有多余的8不能作为开头,那么就将其放到后面去 源代码: #include<cstdio> #include<cctype> #include<algorithm> inline int getint() { regi

Codeforces Round #513(Div.1+Div.2)

闲谈: 重新写博客的第一场比赛,感觉炸裂,成功被Rose和xgcD飞 A 题目: 给出一段长为n个数字字符串,求出能用里面的字符来构成多少个长度为11且开头字符为8的字符串 题解: 直接在n/11和8出现的数量中取min就可以了 参考代码: #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace

Codeforces Round #513解题报告(A~E)By cellur925

我是比赛地址 A:Phone Numbers $Description$:给你一串数字,问你能组成多少开头为8的11位电话号码. $Sol$:统计8的数量,与$n$%11作比较. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 5 using namespace std; 6 7 int n,len,cnt,ans; 8 char ch[1000]; 9 10 int main() 11 {

Codeforces Round #513 D - Social Circles(贪心)

题目大意: 有n(n≤105)个人排成一圈,第i个人要求自己左边空出li个座位,右边空出ri(li,ri≤109)个座位.问最少需要安排多少个座位.思路: 一开始先假设每个人都占了li+ri+1个位置.考虑怎样安排相邻人的顺序,并合并相邻人的li,ri使得答案最优.将所有li,ri分别排序,将对应的li,ri合并一定是最优的(想一想这是为什么). #include <iostream> #include <iomanip> #include <algorithm> #i

Educational Codeforces Round 36 (Rated for Div. 2)

Educational Codeforces Round 36 (Rated for Div. 2) F. Imbalance Value of a Tree You are given a tree T consisting of n vertices. A number is written on each vertex; the number written on vertex i is ai. Let's denote the function I(x,?y) as the differ

Educational Codeforces Round 36 (Rated for Div. 2) 题解

Educational Codeforces Round 36 (Rated for Div. 2) 题目的质量很不错(不看题解做不出来,笑 Codeforces 920C 题意 给定一个\(1\)到\(n\)组成的数组,只可以交换某些相邻的位置,问是否可以将数组调整为升序的 解题思路 首先如果每个数都能通过交换到它应该到的位置,那么就可以调整为升序的. 但实际上交换是对称的,如果应该在的位置在当前位置前方的数都交换完成,那么整体就是排好序的,因为不可能所有不在相应位置的数都在相应位置的后方.