Educational Codeforces Round 1
Educational Codeforces Round 1
https://codeforces.com/contest/598
康复训练day1
1/6:A
A. Tricky Sum
求和公式(等差+等比)
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve () {
int n;
cin >> n;
int t = log2 (n);
//cout << t << ' ';
int sum = n * (n + 1) / 2 - 2 * (pow (2, t + 1) - 1);
cout << sum << endl;
}
signed main () {
int t;
cin >> t;
while (t --) solve ();
}
B. Queries on a String
一开始没看范围想复杂了,其实直接模拟子串的顺序变换即可
#include <bits/stdc++.h>
using namespace std;
void solve () {
string s;
cin >> s;
int m, n = s.size ();
cin >> m;
while (m --) {
int l, r, k;
cin >> l >> r >> k;
l --, r --;
int len = r - l;
if (len == 0) continue;
k %= (len + 1);
string a = s.substr (l, len - k + 1), b = s.substr (l + len - k + 1, k);
//cout << a << ' ' << b << endl;
string c = s.substr (0, l), d = s.substr (r + 1, n - r);
//cout << c << ' ' << d << endl;
s = c + b + a + d;
//cout << s << endl;
}
cout << s << endl;
}
signed main () {
solve ();
}
C. Nearest vectors
题意:给n个向量,找到夹角最小的两个
分析:依次算出每个向量与x正半轴的夹角,然后排序计算两两差值,就可以得到最小。
但是有一些小细节要注意:
- 要用 \(long\,\,double\),不然会被卡精度;
- 因为 \(atan2()\) 的值范围是 \([-\pi,\pi]\),所以当两角差值为负数时,要将差值再加上 \(2\pi\);
- 排序后,\(1\) 和 \(n\) 也是相邻的,不要忘了算这部分。
#include <bits/stdc++.h>
#define PI acos (-1)
#define ld long double
using namespace std;
const int N = 1e5 + 5;
pair<ld, int> a[N];
int main () {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
ld x, y;
cin >> x >> y;
a[i] = {atan2 (y, x), i};
}
sort (a + 1, a + n + 1);
ld minn = 2 * PI;
int ans1, ans2;
//for (int i = 1; i <= n; i++) cout << a[i].first << endl;
for (int i = 2; i <= n; i++) {
ld dx = a[i].first - a[i-1].first;
if (dx < 0) dx += 2 * PI; //!!!
if (dx < minn) {
ans1 = a[i-1].second, ans2 = a[i].second;
minn = dx;
}
}
//1,n
ld dx = a[1].first - a[n].first;
if (dx < 0) dx += 2 * PI;
if (dx < minn) {
ans1 = a[1].second, ans2 = a[n].second;
minn = dx;
}
cout << ans1 << ' ' << ans2 << endl;
}
//算出夹角然后排序
//1和n也相邻啊!!!
D. Igor In the Museum
简单搜索
计算连通块 '.' 周围有几个 '*',注意 '*' 是可以重复计算的,即 搜到一次算一次。
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int N = 1005;
int n, m, k;
char a[N][N];
int ans[N][N];
int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
bool vis[N][N];
bool Range (int x, int y) {
if (x < 0 || x >= n || y < 0 || y >= m) return false;
return true;
}
void bfs (int sx, int sy) {
int sum = 0;
queue <pii> q, q2;
q.push ({sx, sy}), q2.push ({sx, sy});
vis[sx][sy] = true;
while (!q.empty ()) {
auto t = q.front ();
int x = t.first, y = t.second;
q.pop ();
//cout << endl << x << ' ' << y << ": ";
for (int i = 0; i < 4; i++) {
int xx = x + dx[i], yy = y + dy[i];
if (!Range (xx, yy) || vis[xx][yy]) continue;
//cout << xx << ' ' << yy << ", ";
if (a[xx][yy] == '*') sum ++;
else q.push ({xx, yy}), q2.push ({xx, yy}), vis[xx][yy] = true;
}
}
//cout << sum << ' ';
while (!q2.empty ()) {
auto t = q2.front ();
q2.pop ();
int x = t.first, y = t.second;
ans[x][y] = sum;
}
}
int main () {
cin >> n >> m >> k;
for (int i = 0; i < n; i++) cin >> a[i];
//for (int i = 0; i < n; i++) cout << a[i] << endl;
while (k --) {
int x, y;
cin >> x >> y;
x --, y --;
if (!ans[x][y]) bfs (x, y);
cout << ans[x][y] << endl;
}
}
//连通块周围的墙个数,可重
E. Chocolate Bar
题意:在 \(n*m\) 的格子中切出面积 \(k\) 所需的最小代价,只能切一整行 或一整列,代价计算方式为:切下的长度的平方
分析:切割之后的小格子实际上是原格子的子状态,并且划分出该子状态有很多种可能,以及某些子状态可以用某相同状态转移而来。由上述特质可以想到使用动态规划来求解。
设状态 \(f_{i,j,k}\):长为 \(i\),宽为 \(j\),目前需要面积 \(k\)。
转移就是枚举切行/列以及选/不选。
注意初始化 \(f_{i,j,i*j}\),即不需要切的情况
#include <bits/stdc++.h>
using namespace std;
const int N = 35, M = 55;
int f[N][N][M]; //长为i, 宽为j, 目前需要的面积还有k
void pre () {
memset (f, 0x3f, sizeof f);
f[0][0][0] = 0;
for (int i = 0; i <= 30; i ++) {
for (int j = 0; j <= 30; j++) {
if (i * j <= 50) f[i][j][i * j] = 0;
for (int k = 0; k <= 50; k++) {
//行
for (int t = 0; t <= i; t++) {
f[i][j][k] = min (f[i][j][k], f[i - t][j][k] + j * j);
if (k > t * j) f[i][j][k] = min (f[i][j][k], f[i - t][j][k - t * j] + j * j);
}
//列
for (int t = 0; t <= j; t++) {
f[i][j][k] = min (f[i][j][k], f[i][j-t][k] + i * i);
if (k > t * i) f[i][j][k] = min (f[i][j][k], f[i][j-t][k - t * i] + i * i);
}
}
}
}
}
void solve () {
int n, m, k;
cin >> n >> m >> k;
if (k == n * m) {
cout << "0\n";
return ;
}
cout << f[n][m][k] << endl;
}
int main () {
pre ();
int t;
cin >> t;
while (t --) solve ();
}