Educational Codeforces Round 45 Editorial

A. Commentary Boxes

#include<bits/stdc++.h>
#define mem(arry, in) memset(arry, in, sizeof(arry))
using namespace std;
typedef long long ll;
typedef pair<int, int> P;

int main()
{
    ll n, m, a, b;
    cin >> n >> m >> a >> b;
    n = n % m;
    ll res1 = (m - n) * a;
    ll res2 = n * b;
    cout << min(res1, res2) << endl;
}

B. Micro-World

题解:从小到大枚举,观察是否能被前一个(  i + 1 )数消掉。注意相同的数。

#include<bits/stdc++.h>
#define mem(arry, in) memset(arry, in, sizeof(arry))
using namespace std;
typedef long long ll;
typedef pair<int, int> P;

const int maxn = 200005;

int n, K;
int a[maxn], use[maxn * 10];
int main() { cin >> n >> K; for(int i = 1; i <= n; i++){ int tp; cin >> tp; use[tp]++; } int m = 0; for(int i = 1; i <= 1000000; i++) if(use[i]) a[++m] = i; //for(int i = 1; i <= m; i++) cout << a[i] << " "; //cout << endl; int tp = a[1]; int cnt = 0; for(int i = 2; i <= m; i++){ if(a[i] <= tp + K) cnt += use[tp]; tp = a[i]; } cout << n - cnt << endl; return 0; }

C. Bracket Sequences Concatenation Problem

题解:能匹配的情况分别统计一下,比如"(" 和 ")","((" 和 "))",、、、、

#include<bits/stdc++.h>
#define mem(arry, in) memset(arry, in, sizeof(arry))
using namespace std;
typedef long long ll;
typedef pair<int, int> P;

const int maxn = 300005;

int n, cnt, m;
int a[maxn], b[maxn];

stack<char> q;

int main()
{
    while(!q.empty()) q.pop();

    cin >> n;
    cnt = 0;
    for(int i = 0; i < n; i++){
        char s[maxn];
        scanf("%s", s);
        m = strlen(s);

        q.push(s[0]);
        for(int j = 1; j < m; j++){
            if(q.empty()) q.push(s[j]);
            else{
                if(s[j] == ')'){
                    if(q.top() == '(') q.pop();
                    else q.push(s[j]);
                }
                else q.push(s[j]);
            }
        }

        if(q.empty()) cnt++;
        else{
            int g = 0, t = 0;
            while(!q.empty()){
                if(q.top() == '(') g++;
                else t++;
                q.pop();
            }
            if(g && !t) a[g]++;
            if(!g && t) b[t]++;
        }
    }

    ll res = (ll)cnt * (ll)cnt;
    for(int i = 0; i <= maxn; i++) if(a[i] && b[i]) res += (ll)a[i] * (ll)b[i];
    cout << res << endl;
    return 0;
}

 E. Post Lamps

没理解到题意,看代码貌似灯的照亮范围只能选1~k中的一种,所以可以直接暴力求解。n(1 + 1/2 + 1/3 + 1/4 + 1/5 + ·····+ 1/n) = nlog(n)

如果灯的亮度可以在1~k中任意选,感觉会是个背包或者区间DP

#include<bits/stdc++.h>
#define ll long long
#define P pair<int,int>
#define maxn (int)1e6 + 7
#define INF (unsigned long long int)1e18
#define mem(arry, in) memset(arry, in, sizeof(arry))
using namespace std;

int n, m, k;
int use[maxn], a[maxn], s[maxn];

int main()
{
    int tp, l = 0;

    cin >> n >> m >> k;
    for(int i = 1; i <= m; i++) scanf("%d", &tp), use[tp] = 1;
    for(int i = 1; i <= k; i++) scanf("%d", &a[i]);

    if(use[0]) { cout << -1 << endl; return 0; }

    for(int i = 1; i < n; i++){
        if(use[i]) s[i] = s[i - 1] + 1;
        else s[i] = 0;
        l = max(l, s[i]);
    }

    ll res = INF;
    for(int i = l + 1; i <= k; i++){
        int cnt = 0;
        for(int j = 0; j < n; j += i){
            if(use[j]) j -= s[j];
            cnt++;
        }
        res = min(res, (ll)cnt * (ll)a[i]);
    }

    cout << (res == INF ? -1 : res) << endl;
    return 0;
}

F. Flow Control 

题解:如果sigma(a[i])!=0,那么一定不能构造出来。一条边的端点假设是 u, v,对u来说是进流(出流)的边,对v来说必定是出流(进流)的边,所以在 a1 + a2 + a3 + ······ + am 这个式子中,这条边必定出现两次,且互为相反数,故sigma(a[i])=0。对一个点来说只考虑进流和出流的情况,所以构造一颗生成树,树的叶子要么是进流,要么是出流,自底向上计算。

实现的话DFS,不一定用并查集。记录方向也是小技巧。

#pragma warning(disable:4996)
#include<map>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define P pair<int,int>
#define maxn (int)2e5 + 7
#define INF (unsigned long long int)1e18
#define mem(arry, in) memset(arry, in, sizeof(arry))
using namespace std;

int n, m;
int a[maxn], use[maxn], ans[maxn];

vector<P> g[maxn];

void DFS(int u) {
    use[u] = 1;
    for (auto x : g[u]) {
        int v = x.first;
        if (use[v]) continue;
        DFS(v);
        ans[abs(x.second)] = (x.second > 0 ? a[v] : -a[v]);
        a[u] += a[v];
    }
}

int main()
{
    int res = 0;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]), res += a[i];
    scanf("%d", &m);
    for (int i = 1; i <= m; i++) {
        int u, v;
        scanf("%d %d", &u, &v);
        g[u].push_back(P(v, i));
        g[v].push_back(P(u, -i));
    }
    if (res) {
        puts("Impossible");
    }
    else {
        puts("Possible");
        DFS(1);
        for (int i = 1; i <= m; i++) printf("%d\n", ans[i]);
    }
    return 0;
}

 

G. GCD Counting

注意单独的一个点也可以称为一条路径。

超级暴力的做法,以1为根的树,暴力的从叶子向根记录所有路径的gcd值。有小于1s的做法,得去学习一下

vector<int> e[maxn];
map<int, ll> mp[maxn];

int n, a[maxn];
ll cnt[maxn];

int gcd(int a,int b) { return !b ? a : gcd(b, a % b); }

void DFS(int u, int p){
    mp[u][a[u]]++;
    for(int v : e[u]){
        if(v == p) continue;
        DFS(v, u);
        map<int, ll> :: iterator itu, itv;
        for(itu = mp[u].begin(); itu != mp[u].end(); itu++){
            for(itv = mp[v].begin(); itv != mp[v].end(); itv++){
                cnt[gcd(itu->first, itv->first)] += (itu->second * itv->second);
            }
        }
//存子树的gcd值!!!!
for(itv = mp[v].begin(); itv != mp[v].end(); itv++){ mp[u][gcd(a[u], itv->first)] += itv->second; } mp[v].clear(); } }

 

posted @ 2018-06-12 14:36  天之道,利而不害  阅读(142)  评论(0)    收藏  举报