1. 程式人生 > >Codeforces Round #519

Codeforces Round #519

題目連結:傳送門

 

A. Elections (思維+暴力)

思路:

  從最小的k開始列舉就好了- -。

 

#include <bits/stdc++.h>

using namespace std;
const int MAX_N = 100 + 5;

int a[MAX_N];

int main()
{
    int N;
    cin >> N;
    int m = -1, sum = 0;
    for (int i = 1; i <= N; i++) {
        scanf("%d
", a+i); m = max(m, a[i]); sum += a[i]; } int ans = m; int Awruk = N*m-sum; while (Awruk <= sum) { Awruk += N; ans++; } cout << ans << endl; return 0; }
View Code

 

 

 

codeforces1043B. Lost Array (暴力列舉)

思路:

  把差分預處理出來,列舉長度,可以跑到最後的就加入答案。

 

#include <bits/stdc++.h>

using namespace std;
const int MAX_N = 1e3 + 5;

int a[MAX_N];
int b[MAX_N];
int ans[MAX_N];

int main()
{
    int N;
    cin >> N;
    a[0] = 0;
    for (int i = 1; i <= N; i++) {
        scanf("%d", a+i);
        b[i] 
= a[i] - a[i-1]; } int cnt = 0; for (int i = 1; i <= N; i++) { int j; for (j = 1; j <= N; j++) { if (b[j] != b[(j-1)%i+1]) break; } if (j == N+1) ans[cnt++] = i; } cout << cnt << endl << ans[0]; for (int i = 1; i < cnt; i++) cout << ' ' << ans[i]; cout << endl; return 0; }
View Code

 

 

 

codeforces1043C. Smallest Word (思維)

思路:

  遇到連續的a就找到最後一個,翻轉

  遇到連續的b也找到最後一個,如果下一個是a,翻轉

#include <bits/stdc++.h>

using namespace std;
const int MAX_N = 1e3 + 5;

bool ans[MAX_N];

int main()
{
    string s;
    memset(ans, false, sizeof ans);
    cin >> s;
    int len = s.size();
    int i = 0;
    while (i < len) {
        while (i < len && s[i] == 'a')
            i++;
        ans[i-1] = true;
        while (i < len && s[i] == 'b')
            i++;
        if (i < len && s[i] == 'a')
            ans[i-1] = true;
    }
    cout << ans[0];
    for (int i = 1; i < len; i++)
        cout << ' ' << ans[i];
    cout << endl;
    return 0;
}
View Code

 

 

 

codeforces1043D. Mysterious Crime (尺取+暴力)

思路:

  從第一行開始,往下面幾行找最長的匹配。每行從上一行的最左端的數開始往右匹配,匹配到不同的就break,進入下一行。

  預處理一個pos[i][j],表示第i行的值為j的數在哪個位置。

  找完最後一行後得到最長的匹配的長度為len,計算len對答案產生的貢獻

  注意M為1的時候不能匹配特判一下答案就是N*(N+1)/2。

#include <bits/stdc++.h>

using namespace std;
const int MAX_N = 1e5 + 5;
const int MAX_M = 10 + 3;

int N, M;
int a[MAX_M][MAX_N];
int pos[MAX_M][MAX_N];
bool vis[MAX_N];

int main()
{
    cin >> N >> M;
    memset(vis, false, sizeof vis);
    for (int i = 1; i <= M; i++)
        for (int j = 1; j <= N; j++) {
            scanf("%d", &a[i][j]);
            pos[i][a[i][j]] = j;
        }
    long long ans = 0;
    for (int i = 1; i <= N; i++) if (!vis[a[1][i]]){
        int l = i, r = N;
        long long len = 1;
        for (int j = 2; j <= M; j++) {
            int nxtl, nxtr;
            nxtl = nxtr = pos[j][a[j-1][l]];
            while (l <= r && nxtr <= N && a[j][nxtr] == a[j-1][l]) {
                l++;
                nxtr++;
            }
            l = nxtl, r = nxtr-1;
            if (j == M) {
                len = r-l+1;
                for (int k = l; k <= r; k++)
                    vis[a[M][k]] = true;
            }
        }
        ans += (len+1)*len/2;
    }
    if (M == 1)
        ans = (long long)(N+1)*N/2;
    cout << ans << endl;
    return 0;
}
View Code

 

 

 

codeforces1043E. Train Hard, Win Easy(思維+排序)

思路:

  兩個人(u,v)組隊時他們的得分是min(xu+yv,xv+yu),考慮到:

    xu+yv  xv+yu

  =>yv-xv  yu-xu

  令di = yi-xi,則組隊時d小的一方出y,d大的一方出x。

  根據d排序後,對於(1 ≤ i < j N)有di dj,所以第i個人和第j個人組隊的得分為yi+xj

  預處理x和y的字首和,對於第i個人,他與在他之前的人組隊的得分為:

    $\sum_{j=1}^{i-1}y_{j}$ + xi * (i-1);

  與在他之後的人組隊的得分為:

    $\sum_{j=i+1}^{N}x_{j}$ + yi * (N-i);

  這樣可以O(1)算出每個人的得分,然後再減去不能和自己比賽的人的貢獻就好了。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAX_N = 3e5 + 5;

struct Node{
    int ind;
    ll x, y;
    ll d;
    Node(int _i = 0, ll _x = 0, ll _y = 0) : ind(_i), x(_x), y(_y) {d = y-x;}
    bool operator < (const Node& a) const {
        return d < a.d;
    }
}nodes[MAX_N];

ll sumx[MAX_N], sumy[MAX_N];
ll ans[MAX_N];

int main()
{
    int N, M;
    cin >> N >> M;
    memset(ans, 0, sizeof ans);
    for (int i = 1; i <= N; i++) {
        ll x, y;
        scanf("%I64d%I64d", &x, &y);
        nodes[i] = Node(i, x, y);
    }
    for (int i = 1; i <= M; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        ll tmp = 0;
        if (nodes[u] < nodes[v])
            tmp = nodes[u].y + nodes[v].x;
        else
            tmp = nodes[v].y + nodes[u].x;
        ans[u] -= tmp;
        ans[v] -= tmp;
    }
    sort(nodes+1, nodes+1+N);
    sumx[0] = sumy[0] = 0;
    for (int i = 1; i <= N; i++) {
        sumx[i] = sumx[i-1] + nodes[i].x;
        sumy[i] = sumy[i-1] + nodes[i].y;
    }
    for (int i = 1; i <= N; i++) {
        Node cur = nodes[i];
        ans[cur.ind] += sumy[i-1] + cur.x*(i-1);
        ans[cur.ind] += sumx[N] - sumx[i] + cur.y*(N-i);
    }
    bool firstprint = true;
    for (int i = 1; i <= N; i++) {
        if (firstprint)
            firstprint = false;
        else
            printf(" ");
        printf("%I64d", ans[i]);
    }
    puts("");
    return 0;
}
View Code

 

 

 

codeforces1043F. Make It One(組合數學+數論+dp)

思路:

  說實話這題比較玄學。

  2 * 3 * 5 * 7 * 11 * 13 * 17 ≈ 5e5,所以3e5範圍內一個數最多有6個質因數。所以答案是不會超過6的,考慮從1開始列舉答案。

#include <bits/stdc++.h>

using namespace std;
const int MAX_N = 3e5 + 5;
const int MOD = 1e9 + 7;

int fpow(int a, int p) {
    int ans = 1;
    while (p) {
        if (p&1) ans = (1LL * ans * a) % MOD;
        p >>= 1;
        a = (1LL * a * a) % MOD;
    }
    return ans;
}

int N;
int a[MAX_N];
int f[20][MAX_N], cnt[MAX_N];
int fac[MAX_N], inv[MAX_N];

int newton(int m, int n) {
    if (n < 0 || m < n) return 0;
    return ((1LL * fac[m] * inv[n])%MOD * inv[m-n]) % MOD;
}

void init() {
    fac[0] = 1;
    for (int i = 1; i <= MAX_N; i++)
        fac[i] = (1LL * fac[i-1] * i) % MOD;

    inv[MAX_N-1] = fpow(fac[MAX_N-1], MOD-2);
    for (int i = MAX_N-1; i >= 1; i--)
        inv[i-1] = (1LL * inv[i] * i) % MOD;
}

void sub(int& a, int b) {
    a -= b;
    if (a < 0)
        a += MOD;
}

int main()
{
    init();
    scanf("%d", &N);
    memset(cnt, 0, sizeof cnt);
    for (int i = 1; i <= N; i++) {
        scanf("%d", a+i);
        cnt[a[i]]++;
    }
    for (int i = 1; i < MAX_N; i++) {
        for (int j = 2*i; j < MAX_N; j += i) {
            cnt[i] += cnt[j];
        }
    }
    for (int i = 1; i < 20; i++) {
        for (int j = MAX_N-1; j >= 1; j--) {
            f[i][j] = newton(cnt[j], i);
            for (int k = j+j; k < MAX_N; k += j)
                sub(f[i][j], f[i][k]);
        }
        if (f[i][1] > 0) {
            printf("%d\n", i);
            return 0;
        }
    }
    puts("-1");
    return 0;
}
View Code