Codeforces #277.5 (Div.2 A~F)

2024-01-07 17:32
文章标签 codeforces div.2 277.5

本文主要是介绍Codeforces #277.5 (Div.2 A~F),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

比赛地址

Codeforces Round #277.5(Div.2)


489A. SwapSort

题意:

给定一个长度为n的序列,每次可以选择序列中的两个元素交换位置,求任意一组交换次数不超过n次的方案,使交换后的序列是按升序排列的。

n <= 3000。

题解:

我们可以使用选择排序来解决这个问题。

虽然选择排序会进行O(n^2)次比较,但是它具有一个很好的性质,我们可以使它的交换次数是O(n)的。

时间复杂度O(n^2)。

代码:

#include <cstdio>
#include <algorithm>
using namespace std;
int n, a[3333], ans[3333][2], tot;
int main()
{scanf("%d", &n);for(int i = 0; i < n; ++i)scanf("%d", a + i);for(int i = 0; i < n; ++i){int tmp = i;for(int j = i + 1; j < n; ++j)if(a[j] < a[tmp])tmp = j;if(tmp != i){ans[tot][0] = i;ans[tot][1] = tmp;++tot;swap(a[i], a[tmp]);}}printf("%d\n", tot);for(int i = 0; i < tot; ++i)printf("%d %d\n", ans[i][0], ans[i][1]);return 0;
}

489B. BerSU Ball

题意:

有n个男孩、m个女孩参加舞会,每个人有一个舞蹈能力,我们约定一对男女能够一起跳舞,必须满足两人的舞蹈能力之差的绝对值不超过1,求最多能组成多少对男女跳舞。

n, m <= 100。

题解:

我们可以将男孩、女孩的舞蹈能力分别排序,这样可以使得任意一个男生可以共舞的女生是连续的一段,任意一个女生可以共舞的男生是连续的一段。

不难想到用f[i, j]表示前i个男生和前j个女生能成对的数量,将问题转化为dp。时间复杂度O(nm)。

排序后也可以用贪心的算法。时间复杂度O(nlogn)。

代码:

#include <cstdio>
#include <algorithm>
using namespace std;
int n, m, a[233], b[233], f[233][233];
int main()
{scanf("%d", &n);for(int i = 1; i <= n; ++i)scanf("%d", a + i);scanf("%d", &m);for(int i = 1; i <= m; ++i)scanf("%d", b + i);sort(a + 1, a + n + 1);sort(b + 1, b + m + 1);for(int i = 1; i <= n; ++i)for(int j = 1; j <= m; ++j){f[i][j] = max(f[i][j - 1], f[i - 1][j]);if(abs(a[i] - b[j]) <= 1)f[i][j] = max(f[i][j], f[i - 1][j - 1] + 1);}printf("%d\n", f[n][m]);return 0;
}

489C. Give Length and Sum of Digits...

题意:

限定一个数的位数为m,各数位数字之和为s,求这个数可能的最小值和最大值,不存在则输出-1 -1。

m <= 100。

题解:

无解的情况:一是每个位上都是9也无法满足s,即s > 9*m;二是当m>1时s不足1,因为一个m位数最小是10^(m-1)。

这个数的最高位最少是1,其他位最少是0,可以利用贪心的思想构造出最优解,求最小值是尽量用低位去满足s,求最大值则是从高位。

时间复杂度O(m)。

代码:

#include <cstdio>
int m, s, str1[233], str2[233], cnt1, cnt2;
int main()
{scanf("%d%d", &m, &s);if(s == 0){if(m == 1)puts("0 0");elseputs("-1 -1");return 0;}if(s > 9 * m){puts("-1 -1");return 0;}str1[m - 1] = str2[m - 1] = cnt1 = cnt2 = 1;for(int i = 0; i < m && cnt1 < s; ++i)if(cnt1 + 9 - str1[i] < s){cnt1 += 9 - str1[i];str1[i] = 9;}else{str1[i] += s - cnt1;cnt1 = s;}for(int i = m - 1; i >= 0 && cnt2 < s; --i)if(cnt2 + 9 - str2[i] < s){cnt2 += 9 - str2[i];str2[i] = 9;}else{str2[i] += s - cnt2;cnt2 = s;}for(int i = m - 1; i >= 0; --i)putchar('0' + str1[i]);putchar(' ');for(int i = m - 1; i >= 0; --i)putchar('0' + str2[i]);putchar('\n');return 0;
}

489D. Unbearable Controversy of Being

题意:

给定n个点,m条边的有向图,求满足条件"b≠d, a→b→d, a→c→d"的本质不同的四元组(a, b, c, d)的个数,其中(a, b, c, d)与(a, c, b, d)本质相同。

n <= 3000, m <= 30000。

题解:

算出每个点走两步到达另一个点的方案数,通过组合数学知识算出满足条件的(a, *, *, d)的个数。

关于走两步,可以搜索两步,因为每个点的搜索通过的边数量是O(m)的,所以整体算法是O(nm)的。

时间复杂度O(nm)。

代码:

#include <map>
#include <cstdio>
#include <algorithm>
using namespace std;
int n, m;
map<int, int> g1[3010];
int g2[3010];
long long ans;
int main()
{scanf("%d%d", &n, &m);for(int i = 1, u ,v; i <= m; ++i){scanf("%d%d", &u, &v);++g1[u][v];}for(int i = 1; i <= n; ++i){memset(g2, 0, sizeof g2);for(map<int, int>::iterator it1 = g1[i].begin(), jt1 = g1[i].end(); it1 != jt1; ++it1){int j = it1 -> first;for(map<int, int>::iterator it2 = g1[j].begin(), jt2 = g1[j].end(); it2 != jt2; ++it2){int k = it2 -> first;g2[k] += (it1 -> second) * (it2 -> second);}}for(int j = 1; j <= n; ++j)if(i != j && g2[j] >= 2)ans += (long long)g2[j] * (g2[j] - 1) / 2;}printf("%I64d\n", ans);return 0;
}

489E. Hiking

题意:

数轴上有n个点,依次标号1~n,每个点有两个属性,坐标x_i和到达该点可增加的好感度b_i。

规定如果从一个点到另一个点的路程是r,那么这段路程会增加\sqrt{|r - l|}点不适感,其中l为已给定的常数。

求一个运动路线使得从原点开始到达第n个点后的不适感与好感度的比值最小,只能从编号小的点向编号大的点走,保证走的方向一致。

n <= 1000, l <= 10 ^ 5, x_i <= 10 ^ 6。

题解:

经典的分数规划问题。

不妨设最优解的不适感与好感度的比值为k,走过的点数为m,每次增加不适感为p_i,好感度q_i,则\sum_{i = 1} ^ {m} {p_i} /  \sum_{i = 1} ^ {m} {q_i} = k,那么可以转化为\sum_{i = 1} ^ {m} {p_i - k * q_i} = 0。如果给每种可能的路径定义权值为{p_i - k * q_i},则这个式子可以理解为从0点到第n个点的路径上每条边的权值和。则对于给定的答案,我们可以通过计算最短路算出答案是否合法。

如果存在最短路的值不小于0,则该解及比它大的k可能可行。据此可以二分答案k。

时间复杂度O(nlog\sqrt{nx_i})。

代码:

#include <stack>
#include <cstdio>
#include <algorithm>
using namespace std;
const double eps = 1e-10;
int n, l, x[1010], b[1010], p[1010];
bool vis[1010];
double f[1010], L, R, M;
bool judge()
{for(int i = 1; i <= n; ++i){f[i] = sqrt(abs(x[i] - l));p[i] = 0;for(int j = 1; j < i; ++j)if(f[i] > f[j] + sqrt(abs(x[i] - x[j] - l))){f[i] = f[j] + sqrt(abs(x[i] - x[j] - l));p[i] = j;}f[i] -= M * b[i];}return f[n] >= 0;
}
int main()
{scanf("%d%d", &n, &l);for(int i = 1; i <= n; ++i)scanf("%d%d", x + i, b + i);for(M = 1; judge(); M *= 2);L = (int)M / 2;R = M;while(R - L >= eps){M = (L + R) / 2;if(judge())L = M;elseR = M;}stack<int> s;for(int i = n; i; i = p[i])s.push(i);while(!s.empty()){printf("%d ", s.top());s.pop();}putchar('\n');return 0;
}

489F. Special Matrices

题意:

限定一种n*n的01矩阵,它的每行或每列数字之和为2。

现给定一个这种01矩阵的前m行,求这种矩阵有多少种可能的形态,答案可能很大,对一个数取模。

2 <= n <= 500, 0 <= m <= n, 2 <= mod <= 10 ^ 9。

题解:

我们可以统计出有多少个列还差两个1,有多少个列还差一个1,设f[i, j]表示剩i个列差两个1,剩j个列差一个1的方案数,则可以分三种情况讨论填1~2个1之后的状态,利用组合数学推出f[i, j]。

时间复杂度O(n^2)。

代码:

#include <cstdio>
int n, m, mod, r[555], cnt[2], f[555][555];
char str[555];
int main()
{scanf("%d%d%d", &n, &m, &mod);for(int i = 0; i < m; ++i){scanf("%s", str);for(int j = 0; j < n; ++j)if(str[j] == '1')++r[j];}for(int i = 0; i < n; ++i)++cnt[r[i]];f[0][0] = 1;for(int i = 0; i <= cnt[0]; ++i)for(int j = 0; j <= n; ++j){if(i >= 2 && j + 2 <= n){f[i][j] += (long long)i * (i - 1) / 2 * f[i - 2][j + 2] % mod;if(f[i][j] >= mod)f[i][j] -= mod;}if(j >= 2){f[i][j] += (long long)j * (j - 1) / 2 * f[i][j - 2] % mod;if(f[i][j] >= mod)f[i][j] -= mod;}if(i && j){f[i][j] += (long long)i * j * f[i - 1][j] % mod;if(f[i][j] >= mod)f[i][j] -= mod;}}printf("%d\n", f[cnt[0]][cnt[1]]);return 0;
}

小记

考试应该戒骄戒躁;学习算法与实践缺一不可。

这篇关于Codeforces #277.5 (Div.2 A~F)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/580707

相关文章

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

Codeforces 482B 线段树

求是否存在这样的n个数; m次操作,每次操作就是三个数 l ,r,val          a[l] & a[l+1] &......&a[r] = val 就是区间l---r上的与的值为val 。 也就是意味着区间[L , R] 每个数要执行 | val 操作  最后判断  a[l] & a[l+1] &......&a[r] 是否= val import ja

Codeforces Round 971 (Div. 4) (A~G1)

A、B题太简单,不做解释 C 对于 x y 两个方向,每一个方向至少需要 x / k 向上取整的步数,取最大值。 由于 x 方向先移动,假如 x 方向需要的步数多于 y 方向的步数,那么最后 y 方向的那一步就不需要了,答案减 1 代码 #include <iostream>#include <algorithm>#include <vector>#include <string>

Codeforces#295(Div.2)A、B(模拟+BFS)

解题报告链接:点击打开链接 C. 题目链接:点击打开链接 解题思路: 对于给定的字符串,取出现次数最多的字母(可以同时有多个)。由这些字母组成长度为n的字符串,求有多少种组合。最后用数学知识即可。 完整代码: #include <algorithm>#include <iostream>#include <cstring>#include <climits>

Codeforces Round #281 (Div. 2)A(构造+暴力模拟)

题目链接:http://codeforces.com/problemset/problem/493/A 解题思路: 暴力的判断,分三种情况去判断即可。注意如果之前已经被罚下场后,那么在后面的罚下情况不应该算在输出结果内。 完整代码: #include <algorithm>#include <iostream>#include <cstring>#include <co

Codeforces Round #182 (Div. 2)A(水题)

题目链接:http://codeforces.com/contest/302/problem/A 解题思路: 只要通过重新排列使区间内和为0即是1,否则是0. 完整代码: #include <algorithm>#include <iostream>#include <cstring>#include <complex>#include <cstdio>#inc

Codeforces Round #233 (Div. 2)A(构造)

题目链接:http://codeforces.com/contest/399/problem/A 解题思路: 构造出来即可,考虑p-k和p+k两个边界分别于1和n作比较,对左右符号特殊处理。 完整代码: #include <algorithm>#include <iostream>#include <cstring>#include <complex>#include