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

Contest Info


传送门

Solved A B C D E F G H I J K
7 / 11 Ø - O - O O O Ø O - -
  • O 在比赛中通过
  • Ø 赛后通过
  • ! 尝试了但是失败了
  • - 没有尝试

Solutions


A. Average Rank

题意:
\(n\)个人,\(w\)周,初始每个人为\(0\)分。
之后每周会给定一些人,他们的分数会增加\(1\)分,并且所有人的名次也会发生改变(初始所有人的排名都为\(1\))。
分数的改变不会超过\(10^6\)次。
最后问每个人在\(w\)周内排名的平均值为多少,除开初始状态。

思路:
挺考察思维的一个题,显然我们要利用好改变次数不超过\(10^6\)这个条件。
分析一个人的分数由\(x\rightarrow x+1\)所带来的影响:显然他的排名会归类到分数为\(x+1\)的那一档,并且其余分数为\(x\)的人排名会\(+1\)
那么我们对每一类的分数做一个标记,表示当前已经增加了多少,同时还维护一下上一次增加的时间,我们只用在发生改变的时候进行累加即可,而不是每一次改变把这些人都算一次(类似于lazy标记,最后一次我们会将所有标记下放)。
还有些细节,计算贡献时除开时间,还有当前这个人到达\(x\)分段时的答案,这样才能维护变化。
详见代码:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/5/28 16:33:31
 */
#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 = 1e6 + 5;
 
int rk[N], point[N], lazy[N];
ll sum[N], num[N], pre[N];
 
void run() {
    int n, w; cin >> n >> w;
    for (int i = 0; i < N; i++) rk[i] = 1;
    for (int i = 0; i < w; i++) {
        int k; cin >> k;
        for (int j = 0; j < k; j++) {
            int x; cin >> x;
            int& p = point[x];
            num[p] += 1ll * (i - lazy[p]) * rk[p];
            lazy[p] = i;
            ++rk[p];
            sum[x] += num[p] - pre[x];
            
            ++p;
            num[p] += 1ll * (i - lazy[p]) * rk[p];
            lazy[p] = i;
            pre[x] = num[p];
        }
    }
    for (int i = 1; i <= n; i++) {
        int& p = point[i];
        num[p] += 1ll * (w - lazy[p]) * rk[p];
        lazy[p] = w;
        sum[i] += num[p] - pre[i];
        double ans = 1.0 * sum[i] / w;
        cout << ans << '\n';
    }
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

还有另外一种更加巧妙的方法:每次一个人的分数由\(x\rightarrow x+1\),他给分数为\(x\)的这些人所带来的影响是久远的,甚至可能持续到比赛结束(我在说什么?)。并且,他能够追上一些人,这些人目前的分数为\(x+1\),其余的人依旧能给他带来影响。
简单来说,就是维护分数\(>x\)的人的个数,假设为\(k\),那么分数\(=x\)的人的排名就为\(k+1\),如果现在分数为\(x\)的一些人不思进取,前面的每个人始终给他排名\(+1\)。我们直接维护这个值。当一个人分数变为\(x+1\)时,追上了一些人,那么这些人对他暂时没影响了,所以之前他们的贡献会被减去。
说起来挺不好说的,可以看看代码,比较清晰,注意的是还是需要维护一个之前的值,这样才能反映出变化:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/5/28 15:51:27
 */
#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 = 1e6 + 5;
 
int cnt[N];
ll lazy[N], sum[N], pre[N];
int point[N];
 
void run() {
    int n, w; cin >> n >> w;
    cnt[0] = n;
    lazy[0] = w;
    for (int i = 0; i < w; i++) {
        int k; cin >> k;
        for (int j = 1; j <= k; j++) {
            int x; cin >> x;
            int& p = point[x];
            sum[x] += lazy[p] - 1ll * cnt[p + 1] * (w - i) - pre[x];
            lazy[p] += w - i;
            
            --cnt[p];
            ++cnt[++p];
            pre[x] = lazy[p];
        }
    }
    for (int i = 1; i <= n; i++) {
        int p = point[i];
        sum[i] += lazy[p] - pre[i];
        double ans = 1.0 * sum[i] / w;
        cout << ans << '\n';
    }
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

C. Canvas Line

贪心。注意下特殊case。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/5/26 14:56:02
 */
#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 = 1e4 + 5;
 
int n;
struct node {
    int l, r;
} a[N];
 
int p;
int x[N], cnt[N];
 
void run() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i].l >> a[i].r;
    }
    cin >> p;
    for (int i = 1; i <= p; i++) {
        cin >> x[i];
    }
    for (int i = 1; i <= p; i++) {
        for (int j = 1; j <= n; j++) {
            if (a[j].l <= x[i] && x[i] <= a[j].r) {
                ++cnt[j];
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        if (cnt[i] > 2) {
            cout << "impossible" << '\n';
            return;
        }
    }
    vector <int> ans;
    for (int i = 1; i <= n; i++) if (cnt[i] == 0) {
        int p1 = a[i].l, p2 = a[i].r;
        if (i - 1 && a[i - 1].r == p1) {
            if (cnt[i - 1] == 2) ++p1;
            else ++cnt[i - 1];
        }
        if (a[i + 1].l == p2) {
            if (cnt[i + 1] == 2) --p2;
            else ++cnt[i + 1];
        }
        ans.push_back(p1);
        ans.push_back(p2);
        x[++p] = p1, x[++p] = p2;
        cnt[i] = 2;
    }
    for (int i = 1; i <= n; i++) if (cnt[i] == 1) {
        int p1 = a[i].r;
        for (int j = 1; j <= p; j++) {
            if (p1 == x[j]) {
                --p1; break;
            }
        }
        if (a[i + 1].l == p1) {
            if (cnt[i + 1] == 2) --p1;
            else ++cnt[i + 1];
        }
        for (int j = 1; j <= p; j++) {
            if (p1 == x[j]) {
                --p1; break;
            }
        }       
        ans.push_back(p1);
        x[++p] = p1;
    }
    sort(all(ans));
    cout << sz(ans) << '\n';
    for (int i = 0; i < sz(ans); i++) {
        cout << ans[i] << ' ';
    }
    cout << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

E. Expeditious Cubing

签到。

Code
#include<cstdio>
#include<algorithm>
using namespace std;
int main() {
	int a[4];
	for(int i=0; i<4; i++) {
		int b,c;
		scanf("%d.%d", &b, &c);
		a[i]=b*100+c;
	}
	sort(a,a+4);
	int t;
	{
		int b,c;
		scanf("%d.%d", &b, &c);
		t=b*100+c;
	}
	t*=3;
	int s;
	s=a[1]+a[2]+a[3];
	if(s<=t) puts("infinite");
	else {
		int k=t-a[1]-a[2];
		if(k>=a[0]) printf("%d.%02d\n", k/100, k%100);
		else puts("impossible");
	}
}

F. Firetrucks Are Red

最小生成树。

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{}());
vi G[MAXN],G2[MAXN];
int v[MAXN],fa[MAXN];
struct nod{
    int a,b,c;
};
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void run(){
    int n; cin>>n;
    int len=0;
    rep(i,1,n){
        int m;cin>>m;
        while(m--){
            int x; cin>>x;
            G[i].push_back(x);
            v[++len] = x;
        }
    }
    sort(v+1,v+1+len);
    len = unique(v+1,v+1+len) - v-1;
    rep(i,1,n){
        for(int &x:G[i]){
            x = lower_bound(v+1,v+1+len,x)-v;
            G2[x].push_back(i);
        }
    }
    vector<nod> ans;
    rep(i,1,n)fa[i]=i;
    rep(i,1,len){
        for(int j=1;j<sz(G2[i]);j++){
            int x = find(G2[i][j]), y = find(G2[i][j-1]);
            if(x!=y){
                fa[x]=y;
                ans.push_back({G2[i][j-1],G2[i][j],v[i]});
            }
        }
    }
    if(sz(ans)!=n-1){
        cout<<"impossible\n";
        return ;
    }
    for(int i=0;i<sz(ans);i++){
        cout<<ans[i].a<<' '<<ans[i].b<<' '<<ans[i].c<<'\n';
    }
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    int _=1;
    while(_--)run();
    return 0;
}

G. Gnoll Hypothesis

概率题。简单推一推即可。

Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double db;
typedef long double ld;
const int MAXN = 1e3 + 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{}());
ld p[MAXN],co[MAXN];
void run(){
    int n,k;cin>>n>>k;
    rep(i,0,n-1)cin>>p[i],p[i+n]=p[i];
    if(n==1){
        cout<<"100\n";
        return ;
    }
    if(k==1){
        rep(i,0,n-1)printf("%.7Lf%c",(db)100/n," \n"[i==n-1]);
        return ;
    }
    if(n==2){
        if(k==2){
            rep(i,0,n-1)cout<<p[i]<<" \n"[i==n-1];
        }else{
            cout<<"50 50\n";
        }
        return ;
    }
    co[0] = (db)k*(k-1)/n/(n-1);
    rep(j,1,n-k)co[j] = co[j-1]*(db)(n-k-j+1)/(n-j-1);
    rep(i,0,n-1){
        db ans=p[i]*co[0],sum=p[i];
        rep(j,1,n-k){
            sum += p[n+i-j];
            ans += sum * co[j];
        }
        printf("%.7Lf%c",ans," \n"[i==n-1]);
    }
}
int main() {
    //ios::sync_with_stdio(false); cin.tie(0);
    int _=1;
    while(_--)run();
    return 0;
}

H. Height Profile

题意:
给定\(a_{1,2...,n}\),其中\(a_i\)表示高度。
后有\(k\)组询问,每组询问给定一个\(g\),询问斜率不小于\(g\)的最大水平长度为多少。
图片类似于下图:

思路:
就是要求\(\frac{a_j-a_i}{j-i}\geq g\),转化一下即为\(a_j-gj\geq a_i-gi\)
那么我们确定了\(g\),将每个数减去\(gi\),之后排序即可解决问题。
注意一点细节,就是最后的端点可能不为整数,会向斜率较大的一方延伸一部分,这里我们二分一下就行。当然也可以直接用差值比例计算,比较巧妙。
注意一下最后会将\(g\)乘以一个\(10\)变为整数,直接乘可能精度会有误差,比如\(1.0\)在计算机中可能会表示为\(0.9999..\),但乘\(10\)取整就有误差了(当然这只是举个例子)。
二分的话比较繁琐,细节见代码:

Code

I. Inverted Deck

模拟一下找区间就行。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/5/26 14:12:02
 */
#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 = 1e6 + 5;
 
int a[N];
 
void run() {
    int n; cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    int l = 0, r = 0;
    for (int i = 1; i < n; i++) {
        if (a[i] < a[i - 1]) {
            l = i - 1;
            while (l && a[l] == a[l - 1]) --l;
            break;
        }
    }
    for (int i = n - 1; i; i--) {
        if (a[i] < a[i - 1]) {
            r = i;
            while (r + 1 < n && a[r] == a[r + 1]) ++r;
            break;
        }
    }
    if (l <= r) reverse(a + l, a + r + 1);
    for (int i = 1; i < n; i++) {
        if (a[i] < a[i - 1]) {
            cout << "impossible" << '\n';
            return;
        }
    }
    ++l, ++r;
    cout << l << ' ' << r << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}
posted @ 2020-06-06 18:40  heyuhhh  阅读(578)  评论(1编辑  收藏  举报