2018-2019 ICPC Northwestern European Regional Programming Contest (NWERC 2018)


Contest Info


傳送門

Solved A B C D E F G H I J K
8 / 11 Ø O - - Ø - Ø O O Ø O
  • O 在比賽中通過
  • Ø 賽后通過
  • ! 嘗試了但是失敗了
  • - 沒有嘗試

Solutions


A. Access Points

題意:
二維平面中給定\(n\)個點\((x_i,y_i)\)
現在要在二維平面中構造\(n\)個點,其中第\(i\)個點與\((x_i,y_i)\)相連,構造的點可以重合,貢獻為邊權的平方。假設構造的第\(i\)個點為\((X_i,Y_i)\),那么對於\(i<j,X_i\leq X_j,Y_i\leq Y_j\)
問最后最小的貢獻為多少。

思路:

  • 一條邊的貢獻為\((x_i-X_i)^2+(y_i-Y_i)^2\),顯然\(x,y\)獨立,所以我們可以轉化為兩個一維問題。
  • 問題轉化為:數軸上給定\(n\)個點,現在要從小到大依次確定一個點,使得對應的貢獻最小。
  • 考慮\(\sum(x_i-a)^2\)取最小值時,\(a=average(x_i)\),現在問題是\(\sum(x_i-a_i)^2\)最小,直接將\(x\)分為盡可能多的連續的若干段,每一段取平均值即可。
  • 實現的過程可以用一個棧來模擬。

其實就是經典的一個idea的變形,但可以把序列變為連續的若干段,這樣問題就變為經典題目了。
詳見代碼:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/6/10 14:55:43
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#include <functional>
#include <numeric>
#include <stack>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << std::endl; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
void run() {
    int n; cin >> n;
    vector <int> x(n), y(n);
    for (int i = 0; i < n; i++) {
        cin >> x[i] >> y[i];
    }
    
    auto gao = [&] (vector <int>& a) {
        stack <pair <ll, int>> s;
        for (int i = 0; i < n; i++) {
            pair <ll, int> now = MP(a[i], 1);
            while (!s.empty() && s.top().fi * now.se > now.fi * s.top().se) {
                pair <ll, int> t = s.top(); s.pop();
                now.fi += t.fi;
                now.se += t.se;
            }
            s.push(now);
        }
        double res = 0.0;
        int id = n - 1;
        while (!s.empty()) {
            pair <ll, int> t = s.top(); s.pop();
            double ave = 1.0 * t.fi / t.se;
            for (int i = id; i > id - t.se; i--) {
                res += (a[i] - ave) * (a[i] - ave);
            }
            id -= t.se;
        }
        return res;
    };
    
    double ans = 0.0;
    ans += gao(x);
    ans += gao(y);
    cout << ans << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

B. Brexit Negotiations

拓撲序+貪心。
從前往后貪心正確性得不到保障,但是從后往前即可解決這一問題。
很有意思,拓撲序有時候反着來就能解決很多問題QAQ。
代碼寫着較為復雜。。

Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ld;
const int MAXN = 4e5 + 5, MAXM = 4e5 + 5, BOUND = 2e5, MOD = 1e9+7, INF = 0x3f3f3f3f, base = 10000;
const int inv2 = (MOD + 1) >> 1;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0), eps = 1e-9;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define lc(x) ch[x][0]
#define pii pair<int,int>
#define vi vector<int>
#define vii vector<pair<int,int>>
#define rc(x) ch[x][1]
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define all(a) (a).begin(), (a).end()
#define sz(a) int(a.size())
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fi first
#define se second
#define MP std::make_pair
#define ri register int
//#define sz(a) int((a).size())
const int N = 2e5,M = (1<<20);
inline int add(int a, int b) {return a + b >= MOD ? a + b - MOD : a + b;}
inline int dec(int a, int b) {return a < b ? a - b + MOD : a - b;}
inline int mul(int a, int b) {return 1ll * a * b % MOD;}
template <typename T>
inline void cmin(T &a,T b){a = min(a,b);}
template <typename T>
inline void cmax(T &a,T b){a = max(a,b);}
ll qpow(ll a,ll b){
    ll ans=1;
    for(;b;b>>=1,a=a*a%MOD)if(b&1)ans=ans*a%MOD;
    return ans;
}
mt19937 mrand(random_device{}());
int a[MAXN],f[MAXN],in[MAXN];
struct cmp{
    bool operator ()(int u,int v){
        return f[u] < f[v];
    }
};
vi G[MAXN];
bool vis[MAXN];
void dfs(int u){
    vis[u] = 1;
    f[u] = a[u];
    for(int v:G[u]){
        if(!vis[v])dfs(v);
        f[u] = max(f[u], f[v]+1);
    }
}
void run(){
    int n; cin>>n;
    rep(i,1,n){
        cin>>a[i];
        int x; cin>>x;
        rep(j,1,x){
            int u; cin>>u;
            G[u].push_back(i);
            in[i]++;
        }
    }
    rep(i,1,n){
        if(!vis[i]){
            dfs(i);
        }
    }
    priority_queue<int,vector<int>, cmp> q;
    rep(i,1,n)if(!in[i])q.push(i);
    int ans=0,cnt=0;
    while(!q.empty()){
        int u = q.top();q.pop();
        ans = max(ans, cnt + a[u]);
        for(int v:G[u]){
            if((--in[v])==0){
                q.push(v);
            }
        }
        cnt++;
    }
    cout<<ans<<'\n';
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    //freopen("A.in","r",stdin);
    //freopen("A.out","w",stdout);
    int _=1;
    while(_--)run();
    return 0;
}

E. Equality Control

題意:
給定兩個表達式,每個表達式有"combine","sorted","shuffle","[]"這四種運算符。其中"[]"中間有一個序列,形如\(x_1,x_2,\cdots,x_i\)
現在問這兩個表達式是否等價。表達式等價的定義為出現每一種序列的概率都相同。

思路:
首先有幾個觀察:

  • 形如shuffle[1,1,1,1]這種相當於沒有進行操作;
  • 無視combine操作;
  • 表達式樹中,如果某個結點出現了sorted或者shuffle,那么其葉子結點都沒用了,最后只取決於它。

根據這三點很容易看兩個表達式最后是否相等了,但是題目要求出現的概率相等。
那么再加一個條件,在滿足數列相等后,所有shuffle的區間都相等就行(此時概率肯定相等)。如果存在一個區間不相等,那么最后兩個式子肯定不等價。
詳見代碼:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/6/9 23:22:06
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#include <functional>
#include <numeric>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << std::endl; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
typedef pair <vector <int>, vector<pii>> result;
 
result get(string& s) {
    int n = s.length();
    vector <int> a, sum(n, -1);
    for (int i = 0, j; i < n; i = j + 1) {
        j = i;
        if (s[i] >= '0' && s[i] <= '9') {
            int x = 0;
            while (j < n && s[j] >= '0' && s[j] <= '9') {
                x = x * 10 + (s[j] - '0');
                ++j;
            }
            sum[j - 1] = sz(a);
            a.push_back(x);
        }
    }
    vector <pii> seg;
    for (int i = 0, j; i < n; i = j + 1) {
        j = i;
        if (s[i] != 's') continue;
        int cnt = 0;
        while (j < n && (s[j] < '0' || s[j] > '9')) {
            if (s[j] == '(') ++cnt;
            ++j;
        }
        int L = INF, R = -1;
        while (j < n && cnt > 0) {
            if (s[j] == '(') ++cnt;
            if (s[j] == ')') --cnt;
            if (sum[j] != -1) {
                L = min(L, sum[j]);
                R = max(R, sum[j]);
            }
            ++j;
        }
        if (L > R) continue;
        sort(a.begin() + L, a.begin() + R + 1);
        if (s[i + 1] == 'h' && a[L] != a[R]) {
            seg.push_back(MP(L, R));
        }
    }
    return MP(a, seg);
}
 
void run() {
    string s, t; cin >> s >> t;
    result A = get(s), B = get(t);
    if (A == B) {
        cout << "equal" << '\n';
    } else {
        cout << "not equal" << '\n';
    }
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

G. Game Design

題意:
給定一些操作符"LRUD",表示往某一個方向走直到遇到障礙。
現在給定終點\((0,0)\),要求構造一個起點以及若干障礙物,使得最后小球能夠到達終點。注意必須是最后一步到達終點,中間到達終點即不合法。
大概圖就是這個樣子:

思路:
一般這種題都會考慮從后往前構造,但這個題中從后往前構造可能會很麻煩。
注意到我們終點的具體位置不重要,假設我們最后到達了某個點\((x,y)\),直接將坐標軸相對於\((x,y)\)平移即可。
所以問題就轉化為了從\((0,0)\)出發,構造一種方案,使得存在一種合法的路徑。
到了這一步就比較簡單了。網格圖中的移動一般是規定一個范圍,每一次范圍會變大或減小。因為這個題從\((0,0)\)開始走,所以我們不斷將范圍變大並且每次走到邊界即可,只要保證小球不會在路徑上碰到障礙物就行。
注意特殊情況:LRL,RLR,UDU,DUD出現在了末尾則肯定不合法,若中間為LRLRLR這種則不擴大范圍。
細節見代碼:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/6/9 15:25:32
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#include <functional>
#include <numeric>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << std::endl; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 20 + 5;
 
int n;
string s;
int d;
 
map <int, map<int, int>> mp;
 
void sayNo() {
    cout << "impossible" << '\n';
    exit(0);   
}
 
void run() {
    cin >> s;
    n = s.length();
    if (n >= 3 && s[n - 1] == s[n - 3]) {
        if (s[n - 1] == 'L' && s[n - 2] == 'R') sayNo();
        if (s[n - 1] == 'R' && s[n - 2] == 'L') sayNo();
        if (s[n - 1] == 'U' && s[n - 2] == 'D') sayNo();
        if (s[n - 1] == 'D' && s[n - 2] == 'U') sayNo();
    }
    d = 1;
    int x = 0, y = 0;
    vector <pii> ans;
    for (int i = 0; i < n; i++) {
        if (s[i] == 'R') {
            x = d;
            ans.push_back(MP(x + 1, y));
        }
        if (s[i] == 'L') {
            x = -d;
            ans.push_back(MP(x - 1, y));
        }
        if (s[i] == 'D') {
            y = -d;
            ans.push_back(MP(x, y - 1));
        }
        if (s[i] == 'U') {
            y = d;
            ans.push_back(MP(x, y + 1));
        }
        if (i + 1 < n) {
            if (s[i] == 'L' && s[i + 1] == 'R') {}
            else if (s[i] == 'R' && s[i + 1] == 'L') {}
            else if (s[i] == 'U' && s[i + 1] == 'D') {}
            else if (s[i] == 'D' && s[i + 1] == 'U') {}
            else d += 2;
        }
    }
    
    cout << -x << ' ' << -y << '\n';
    sort(all(ans));
    ans.erase(unique(all(ans)), ans.end());
    cout << sz(ans) << '\n';
    for (auto it : ans) {
        cout << it.fi - x << ' ' << it.se - y << '\n';
    }
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

H. Hard Drive

貪心一下就行。
從后往前插入\(1\),我們首先想讓他貢獻\(2\)次,如果是偶數就很簡單,奇數會多一次我們插在\(1\)位置即可。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/6/9 13:31:53
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#include <functional>
#include <numeric>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << std::endl; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
void run() {
    int n, c, b;
    cin >> n >> c >> b;
    vector <int> a(n, -1);
    for (int i = 0; i < b; i++) {
        int x; cin >> x; --x;
        a[x] = 0;
    }
    int t = c / 2;
    for (int i = n - 2; i >= 0 && t; i--) {
        if (a[i] == -1) {
            a[i] = 1;
            --t; --i;
        }
    }
    if (c & 1) {
        a[0] = 1;
    }
    for (int i = 0; i < n; i++) {
        if (a[i] == -1) a[i] = 0;
        cout << a[i];   
    }
    cout << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

I. Inflation

簽到。

Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ld;
const int MAXN = 2e5 + 5, MAXM = 4e5 + 5, BOUND = 2e5, MOD = 1e9+7, INF = 0x3f3f3f3f, base = 10000;
const int inv2 = (MOD + 1) >> 1;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0), eps = 1e-9;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define lc(x) ch[x][0]
#define pii pair<int,int>
#define vi vector<int>
#define vii vector<pair<int,int>>
#define rc(x) ch[x][1]
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define all(a) (a).begin(), (a).end()
#define sz(a) int(a.size())
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fi first
#define se second
#define MP std::make_pair
#define ri register int
//#define sz(a) int((a).size())
const int N = 2e5,M = (1<<20);
inline int add(int a, int b) {return a + b >= MOD ? a + b - MOD : a + b;}
inline int dec(int a, int b) {return a < b ? a - b + MOD : a - b;}
inline int mul(int a, int b) {return 1ll * a * b % MOD;}
template <typename T>
inline void cmin(T &a,T b){a = min(a,b);}
template <typename T>
inline void cmax(T &a,T b){a = max(a,b);}
ll qpow(ll a,ll b){
    ll ans=1;
    for(;b;b>>=1,a=a*a%MOD)if(b&1)ans=ans*a%MOD;
    return ans;
}
mt19937 mrand(random_device{}());
int c[MAXN];
void run(){
    int n; cin>>n;
    rep(i,1,n)cin>>c[i];
    sort(c+1,c+1+n);
    db frac = 1;
    rep(i,1,n){
        if(c[i]>i){
            cout<<"-1\n";
            return ;
        }
        frac = min(frac,(db)c[i]/i);
    }
    printf("%.6f\n",frac);
}
int main() {
    //ios::sync_with_stdio(false); cin.tie(0);
    int _=1;
    while(_--)run();
    return 0;
}

J. Jinxed Betting

假設當前除開第一個人其余分數最大值為\(MAX\),有\(cnt\)個。並且現在最大和次大的差值為\(d\)
顯然模擬一下會發現經過\(log_2\lfloor\frac{cnt}{2}\rfloor\)次過后\(MAX\)會加一,並且再經過一次\(d\)會減少\(1\)
也就是一個過程我們可以看作\(log_2\lfloor\frac{cnt}{2}\rfloor+1\)步,對於每一個值來說會重復\(d\)次,之后會更新\(MAX,cnt\)並且繼續執行以上操作直到\(MAX\)超過\(a[0]\)
那么手動模擬一下這個過程即可,注意一下邊界的情況。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/6/9 22:17:52
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#include <functional>
#include <numeric>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << std::endl; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
void run() {
    int n; cin >> n;
    vector <ll> a(n);
    vector <int> lg(N);
    lg[2] = 1;
    for (int i = 3; i < N; i++) {
        lg[i] = lg[i >> 1] + 1;
    }
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    sort(all(a));
    reverse(all(a));
    int t = 1;
    ll ans = 0, Max = a[1];
    while (1) {
        while (t + 1 < n && a[t + 1] == a[t]) ++t;
        if (t == n - 1) {
            int k = lg[t];
            ll D = a[0] - Max;
            ll A = D / k;
            Max += A * k;
            ans += 1ll * (k + 1) * A;
            ans += D % k;
            break;           
        } else {
            ll d = a[t] - a[t + 1];
            int k = lg[t]; //+=k
            if (1ll * k * d + Max <= a[0]) {
                Max += 1ll * k * d;
                ans += 1ll * (k + 1) * d;
            } else {
                ll D = a[0] - Max;
                ll A = D / k;
                Max += A * k;
                ans += 1ll * (k + 1) * A;
                ans += D % k;
                break;
            }
        }
        ++t;
    }
    cout << ans << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

K. Kleptography

簽到。

Code
#include<cstdio>
using namespace std;
char enc[107];
char orn[107];
int main() {
	int n, m; scanf("%d%d", &n, &m);
	scanf("%s%s", orn+m-n, enc);
 
	for(int i=m-n-1, j=m-1; i>=0; i--, j--) {
		orn[i]=(enc[j]-orn[j]+26)%26+'a';
	}
	printf("%s\n", orn);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM