@Dmaxiya
2018-08-17T10:15:53.000000Z
字数 10607
阅读 984
Codeforces
Contests 链接:Codeforces Round #502 (Div. 1 + Div. 2)
过题数:4
排名:765/7399
一个班上有 个学生,每个学生都有一个 和四门课的成绩,每个学生的 为 到 之间的整数,每个学生的 都不相同,将所有学生按总分从高到低排序,若总分相同则按 从小到大排序,问 为 的学生最终排在第几名。
第一行为一个整数 ,接下去 行每行 个整数 ,第 行的 个整数表示 号为 的学生四门课的成绩。
输出最终 为 的学生的排名。
输入 |
---|
5 100 98 100 100 100 100 100 100 100 100 99 99 90 99 90 100 100 98 60 99 |
输出 |
2 |
提示 |
个学生的总分分别为 , 为 的学生的分数和 为 的分数相等,但是他的 值更小,所以他排在第 名。 |
输入 |
---|
6 100 80 90 99 60 60 60 60 90 60 100 60 60 100 60 80 100 100 0 100 0 0 0 0 |
输出 |
1 |
提示 |
个学生的总分分别为 , 为 的学生分数最高,所以他是第 名。 |
按照总分为主关键字, 为次关键字排序,然后 扫一遍找到 为 的学生的排名。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <algorithm>
#include <functional>
#include <iomanip>
using namespace std;
#define LL long long
const int maxn = 1000 + 100;
struct Node {
int sum, id;
};
bool operator<(const Node &a, const Node &b) {
return a.sum == b.sum? a.id < b.id: a.sum > b.sum;
}
int n, num;
Node node[maxn];
int main() {
#ifdef LOCAL
freopen("test.txt", "r", stdin);
// freopen("test1.out", "w", stdout);
#endif // LOCAL
ios::sync_with_stdio(false);
while(scanf("%d", &n) != EOF) {
for(int i = 1; i <= n; ++i) {
node[i].sum = 0;
node[i].id = i;
for(int j = 0; j < 4; ++j) {
scanf("%d", &num);
node[i].sum += num;
}
}
sort(node + 1, node + 1 + n);
int ans = 0;
for(int i = 1; i <= n; ++i) {
if(node[i].id == 1) {
ans = i;
break;
}
}
printf("%d\n", ans);
}
return 0;
}
给定由 个 位组成的二进制数 和 ,问对 的所有 位有多少种交换不同位的方式,使得 (按位或)的值发生改变。
第一行为一个整数 ,第 行为 个 字符,表示 的所有二进制位,第 行为 个 字符,表示 的二进制位。
输出方案数。
输入 |
---|
5 01011 11001 |
输出 |
4 |
提示 |
中可以交换的 位为:。 |
输入 |
---|
6 011000 010011 |
输出 |
6 |
提示 |
中可以交换的 位为:。 |
枚举所有 和 中 位的对应情况:
- 为 的位对应的是 为 的位,与另一个 为 的位交换,当前位置上的或值将会从 变为 ;
- 为 的位对应的是 为 的位,与另一个 为 而 为 的位交换,那么被交换的位置上的或值将会从 变为 ;
- 为 的位对应的是 为 的位,与另一 为 的位交换,当前位置上的或值将会从 变为 ;
- 为 的位对应的是 为 的位,与另一个 为 而 为 的位交换,被交换的位置上的或值将会从 变为 。
因此按照所有对应位置上 的 状态求前缀和或者后缀和,最后 扫一遍就能得到答案。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <algorithm>
#include <functional>
#include <iomanip>
using namespace std;
#define LL long long
const int maxn = 100000 + 100;
int n;
int sum[maxn][4];
char a[maxn], b[maxn];
int id(int i) {
return (a[i] - '0') * 2 + b[i] - '0';
}
int main() {
#ifdef LOCAL
freopen("test.txt", "r", stdin);
// freopen("test1.out", "w", stdout);
#endif // LOCAL
ios::sync_with_stdio(false);
while(scanf("%d", &n) != EOF) {
memset(sum, 0, sizeof(sum));
scanf("%s%s", a + 1, b + 1);
for(int i = n; i > 0; --i) {
for(int j = 0; j < 4; ++j) {
sum[i][j] = sum[i + 1][j];
}
++sum[i][id(i)];
}
LL ans = 0;
for(int i = 1; i < n; ++i) {
switch(id(i)) {
case 0: ans += sum[i + 1][2] + sum[i + 1][3]; break;
case 1: ans += sum[i + 1][2]; break;
case 2: ans += sum[i + 1][0] + sum[i + 1][1]; break;
case 3: ans += sum[i + 1][0]; break;
default: break;
}
}
printf("%I64d\n", ans);
}
return 0;
}
构造一个 到 的排列,使得这个排列中最长上升子序列的长度加上最长下降子序列的长度最小。
输入为一个整数 。
输出 个整数,为 到 的排列,如果有多解输出任意一组。
输入 |
---|
4 |
输出 |
3 4 1 2 |
提示 |
最长上升子序列的长度为 ,最长下降子序列的长度为 ,总和为 ,是所有排列中最小的,但不是唯一的答案。 |
输入 |
---|
2 |
输出 |
2 1 |
提示 |
最长上升子序列的长度为 ,最长下降子序列的长度为 ,总和为 ,是所有排列中最小的,但不是唯一的答案,序列 也是合法的答案。 |
将 分成 块3,其中每一块中的数字是递增的,各个块之间是递减的,则最长上升子序列的长度和最长下降子序列的长度和最小,为 ,由基本不等式可知,当 为 时 的值最小。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <algorithm>
#include <functional>
#include <iomanip>
using namespace std;
#define LL long long
const int maxn = 100000 + 100;
int n;
int num[maxn];
int main() {
#ifdef LOCAL
freopen("test.txt", "r", stdin);
// freopen("test1.out", "w", stdout);
#endif // LOCAL
ios::sync_with_stdio(false);
while(scanf("%d", &n) != EOF) {
int Index = sqrt(n);
int tmp = 1;
int Min = n;
for(int i = n - Index; i >= 0; i -= Index) {
Min = i;
for(int j = 0; j < Index; ++j) {
num[i + j] = tmp++;
}
}
for(int i = 0; i < Min; ++i) {
num[i] = tmp++;
}
for(int i = 0; i < n; ++i) {
if(i != 0) {
printf(" ");
}
printf("%d", num[i]);
}
printf("\n");
}
return 0;
}
有一个元素个数为 的 串集合,集合内的 串可以重复出现,且每一个串的长度都为 ,对于两个 串 和 ,它们产生的价值为 ,现在有 次询问,每次询问由一个长度为 的 串 和一个数 组成,询问集合中满足条件 的字符串个数。
第一行为 个整数 。第二行为 个整数 ,接下去 行每行一个长度为 的 字符串,接下去 行每行由一个长度为 的 字符串和 组成。
对于每次询问,输出答案。
输入 |
---|
2 4 5 40 20 01 01 10 11 00 20 00 40 11 20 11 40 11 60 |
输出 |
2 4 2 3 4 |
输入 |
---|
1 2 4 100 0 1 0 0 0 100 1 0 1 100 |
输出 |
1 2 1 2 |
先将字符串转化为对应数字( 到 ),对于集合中的所有数字 ,统计每个数字出现的次数 ,接着对所有可能的询问 ( 到 )都预处理出对应的价值 ,将价值为 的集合中的数字 的个数记录在 中,即 ,由于询问中的 最大值为 ,所以 数组的第 维只需要开到 ,大于 的可以不用处理,最后对 的每一次询问 都做一遍前缀和,就能得到询问为 时,价值小于等于 的所有满足条件的 的个数。预处理和查询的时间复杂度为 。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <algorithm>
#include <functional>
#include <iomanip>
using namespace std;
#define LL long long
int n, m, k, q;
char str[20];
int num[20], cnt[4096];
int sum[4096 + 100][100 + 20];
int main() {
#ifdef LOCAL
freopen("test.txt", "r", stdin);
// freopen("test1.out", "w", stdout);
#endif // LOCAL
ios::sync_with_stdio(false);
while(scanf("%d%d%d", &n, &m, &q) != EOF) {
memset(cnt, 0, sizeof(cnt));
memset(sum, 0, sizeof(sum));
for(int i = 0; i < n; ++i) {
scanf("%d", &num[i]);
}
for(int i = 0; i < m; ++i) {
scanf("%s", str);
int tmp = 0;
for(int j = 0; j < n; ++j) {
tmp |= (str[j] - '0') << j;
}
++cnt[tmp];
}
for(int i = 0; i < (1 << n); ++i) {
for(int j = 0; j < (1 << n); ++j) {
int tmp = 0;
for(int k = 0; k < n; ++k) {
if(((i >> k) & 1) == ((j >> k) & 1)) {
tmp += num[k];
}
}
if(tmp > 100) {
continue;
}
sum[i][tmp] += cnt[j];
}
}
for(int i = 0; i < (1 << n); ++i) {
for(int j = 1; j <= 100; ++j) {
sum[i][j] += sum[i][j - 1];
}
}
for(int i = 0; i < q; ++i) {
scanf("%s%d", str, &k);
int tmp = 0;
for(int j = 0; j < n; ++j) {
tmp |= (str[j] - '0') << j;
}
printf("%d\n", sum[tmp][k]);
}
}
return 0;
}
有两个点集,点的个数分别为 和 ,问两个点集分别构成的凸包是否可以通过旋转、平移使得两个凸包完全重合。
第一行包含两个整数 ,接下去 行每行两个整数 ,表示第一个点集中每个点的坐标,最后 行每行两个整数 ,表示第二个点集中每个点的坐标,其中 。
如果可以通过旋转与平移使两个凸包完全重合,输出 ,否则输出 ,大小写任意。
输入 |
---|
3 4 0 0 0 2 2 0 0 2 2 2 2 0 1 1 |
输出 |
YES |
提示 |
点集在平面直角坐标系上的位置为: 将第一个点集旋转 后: 再将第二个点集平移 后: |
输入 |
---|
3 4 0 0 0 2 2 0 0 2 2 2 2 0 0 0 |
输出 |
NO |
提示 |
不论如何平移旋转,两个凸包都不会重合。 |
先分别跑出两个点集的凸包,判定两个凸包可以旋转平移重合的条件是:每条对应边的长度相等且对应角的大小相等,对应边直接求边长平方,对应角可以用叉积。将其中一个点集在凸包上所有点都复制到最后,让另一个凸包的所有点在这上面跑一遍 , 能够往后跑的条件就是对应边与对应角都相等。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <algorithm>
#include <functional>
#include <iomanip>
using namespace std;
#define LL long long
const int maxn = 100000 + 100;
struct Point {
LL x, y;
Point() {}
Point(LL xx, LL yy) {
x = xx;
y = yy;
}
};
LL operator*(const Point &a, const Point &b) {
return a.x * b.x + a.y * b.y;
}
bool operator<(const Point &a, const Point &b) {
return a.x == b.x? a.y < b.y: a.x < b.x;
}
LL operator^(const Point &a, const Point &b) {
return a.x * b.y - a.y * b.x;
}
Point operator-(const Point &a, const Point &b) {
return Point(a.x - b.x, a.y - b.y);
}
struct Cross_len {
LL cross, len;
};
bool operator==(const Cross_len &a, const Cross_len &b) {
return a.cross == b.cross && a.len == b.len;
}
bool operator!=(const Cross_len &a, const Cross_len &b) {
return !(a == b);
}
int n[2], top[2];
Point point[2][maxn], sta[2][maxn << 1];
int Next[maxn];
Cross_len cross_len[2][maxn << 1];
void ConvexHull(Point *p, int n, int &top, Point *sta) {
top = 0;
sort(p + 1, p + 1 + n);
for(int i = 1; i <= n; ++i) {
while(top > 1 && ((sta[top - 1] - sta[top - 2]) ^ (p[i] - sta[top - 2])) <= 0) {
--top;
}
sta[top++] = p[i];
}
int ttop = top;
for(int i = n; i > 0; --i) {
while(top > ttop && ((sta[top - 1] - sta[top - 2]) ^ (p[i] - sta[top - 2])) <= 0) {
--top;
}
sta[top++] = p[i];
}
--top;
}
void Change_to_Cross_len(Point *p, int n, Cross_len *c) {
Point p0 = p[0];
for(int i = 0; i < n - 1; ++i) {
p[i] = p[i + 1] - p[i];
c[i].len = p[i] * p[i];
}
p[n - 1] = p0 - p[n - 1];
c[n - 1].len = p[n - 1] * p[n - 1];
for(int i = 0; i < n; ++i) {
c[i].cross = p[i] ^ p[(i + 1) % n];
}
}
void get_next(Cross_len *str, int n) {
int j = -1;
Next[0] = -1;
for(int i = 1; i < n; ++i) {
while(j != -1 && str[j + 1] != str[i]) {
j = Next[j];
}
if(str[i] == str[j + 1]) {
++j;
}
Next[i] = j;
}
}
bool kmp(Cross_len *str1, int n, Cross_len *str2, int m) {
int j = -1;
for(int i = 0; i < n; ++i) {
while(j != -1 && str1[i] != str2[j + 1]) {
j = Next[j];
}
if(str1[i] == str2[j + 1]) {
++j;
}
if(j == m - 1) {
return true;
}
}
return false;
}
int main() {
#ifdef LOCAL
freopen("test.txt", "r", stdin);
// freopen("test1.out", "w", stdout);
#endif // LOCAL
ios::sync_with_stdio(false);
while(scanf("%d%d", &n[0], &n[1]) != EOF) {
memset(point, 0, sizeof(point));
for(int i = 0; i < 2; ++i) {
for(int j = 1; j <= n[i]; ++j) {
scanf("%I64d%I64d", &point[i][j].x, &point[i][j].y);
}
ConvexHull(point[i], n[i], top[i], sta[i]);
if(i == 0) {
for(int j = 0; j < top[i]; ++j) {
sta[i][j + top[i]] = sta[i][j];
}
top[i] *= 2;
}
Change_to_Cross_len(sta[i], top[i], cross_len[i]);
}
get_next(cross_len[1], top[1]);
if(kmp(cross_len[0], top[0], cross_len[1], top[1])) {
printf("Yes\n");
} else {
printf("No\n");
}
}
return 0;
}
注意本题内存限制为 。
定义函数:
设 ,其中的每个 是 的质因数, 值是质因数对应的指数。
给定整数 和参数 的值,计算以下公式:
输入包含 个整数 。
将计算结果对 取模后输出。
输入 |
---|
12 0 0 1 0 |
输出 |
63 |
输入 |
---|
4 1 2 3 4 |
输出 |
136 |
从 到 内每个质数 对答案的贡献为 ,其中 为满足 的最大值,因此最后的答案就是:
对 取模,就是用unsigned int
进行计算并让它们自然溢出。
最后是内存限制,如果我们用一个线性筛,就需要存每个数字是否是质数,如果用bool
数组, 的bool
数组需要 ,用bitset
压位需要 ,如果用埃氏筛,就可以在筛的过程中跳过 和 的倍数,我们将删去 和 的倍数后连续的数字用对应的 表示:
可以发现数字与下标之间是 的关系,因此如果跳过 和 的倍数,可以减少 的空间,最后只需要 。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <algorithm>
#include <functional>
#include <iomanip>
using namespace std;
#define LL long long
unsigned n, a, b, c, d;
unsigned ans;
bitset<100000001> bit;
unsigned f(unsigned x) {
return a * x * x * x + b * x * x + c * x + d;
}
unsigned Get(unsigned x) {
unsigned ret = f(x);
unsigned tmp = 0;
for(unsigned i = 1; i <= n / x; i *= x) {
tmp += n / (i * x);
}
return ret * tmp;
}
int main() {
#ifdef LOCAL
freopen("test.txt", "r", stdin);
// freopen("test1.out", "w", stdout);
#endif // LOCAL
ios::sync_with_stdio(false);
while(cin >> n >> a >> b >> c >> d) {
ans = Get(2) + Get(3);
bit.reset();
for(unsigned i = 5; i <= n; ++i) {
if(i % 2 == 0 || i % 3 == 0) {
continue;
}
if(bit[i / 3] == 0) {
ans += Get(i);
for(unsigned j = i; j <= n / i; ++j) {
if(i * j % 2 == 0 || i * j % 3 == 0) {
continue;
}
bit[i * j / 3] = 1;
}
}
}
cout << ans << endl;
}
return 0;
}