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正半轴的夹角,然后排序计算两两差值,就可以得到最小。

但是有一些小细节要注意:

  1. 要用 \(long\,\,double\),不然会被卡精度;
  2. 因为 \(atan2()\) 的值范围是 \([-\pi,\pi]\),所以当两角差值为负数时,要将差值再加上 \(2\pi\)
  3. 排序后,\(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 ();
}

F. Cut Length

posted @ 2022-12-15 23:41  Sakana~  阅读(30)  评论(0编辑  收藏  举报