首页 > 其他分享 >2019-2020 ICPC Northwestern European Regional Programming Contest (NWERC 2019)

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

时间:2024-02-04 19:26:29浏览次数:35  
标签:std Northwestern return Contest int second 2019 include define

Preface

由于前两天疑似感染风寒,今天头痛+鼻塞+咽炎一条龙,硬打了4h顶不住就下班了

最后过了8个题也还行,比较可惜的就是H题从中期写到结束,祁神和徐神各写了一个version也没过


A. Average Rank

挺有意思的一个题

考虑将一个原来分数为\(x\)的人加\(1\)分后会发生什么,显然只有原来分数也为\(x\)分的人的排名往后移了一位

直接暴力维护是\(O(nw)\)的,但我们仔细一想可以记录一下每个分数上一次更新的时间,以此略过不受影响的排名

#include<cstdio>
#include<iostream>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
const int N=300005;
int n,w,x,y,p[N],rk[N],lst[N],sum[N],coef[N],pre[N];
signed main()
{
	RI i,j; for (scanf("%lld%lld",&n,&w),i=0;i<=w;++i) lst[i]=1;
	for (i=1;i<=w;++i)
	{
		for (scanf("%lld",&x),j=1;j<=x;++j)
		{
			scanf("%lld",&y); coef[p[y]]+=rk[p[y]]*(i-lst[p[y]]);
			lst[p[y]]=i; ++rk[p[y]]; sum[y]+=coef[p[y]]-pre[y];
			++p[y]; coef[p[y]]+=rk[p[y]]*(i-lst[p[y]]);
			lst[p[y]]=i; pre[y]=coef[p[y]];
		}
	}
	for (i=1;i<=n;++i)
	{
		coef[p[i]]+=rk[p[i]]*(w+1-lst[p[i]]);
		lst[p[i]]=w+1; sum[i]+=coef[p[i]]-pre[i];
		printf("%.9lf\n",(1.0*sum[i]/w+1.0));
	}
	return 0;
}

B. Balanced Cut

应该是本场的防AK题,做不来一点


C. Canvas Line

徐神写的,我题目都没看

#include <bits/stdc++.h>

int n, p;
std::map<int, std::pair<int, int>> canvas;
std::set<int> pegs, at;

using mit = std::map<int, std::pair<int, int>>::iterator;

mit get_next(mit it) {
    if(it == canvas.end()) return it;
    int r = it->second.first;
    ++it; if(it == canvas.end()) return it;
    return it->first == r ? it : canvas.end();
}

bool try_put(int x, bool ne = false) {
    if(pegs.find(x) != pegs.end()) return false;
    auto it = canvas.lower_bound(x);
    if(x == it->first) {
        if(it->second.second == 2) return false;
        if(it != canvas.begin()) {
            auto pre = it; --pre;
            if(pre->second.first == x) {
                if(pre->second.second == 2) return false;
                pre->second.second += 1;
                ne = true;
            }
        }
        it->second.second += 1; ne = true;
    } else if(it != canvas.begin()) {
        --it;
        if(it->first <= x && x <= it->second.first) {
            if(it->second.second == 2) return false;
            it->second.second += 1; ne = true;
        } 
    }
    if(ne) pegs.insert(x);
    return true;
}

int main(void) {
    std::ios::sync_with_stdio(false);
    std::cin >> n;
    for(int i = 0, l, r; i < n; ++i) {
        std::cin >> l >> r;
        canvas[l] = {r, 0};
    }
    std::cin >> p;
    for(int i = 0, x; i < p; ++i) {
        std::cin >> x; at.insert(x);
        if(!try_put(x, true)) return std::cout << "impossible\n", 0;
    }
    for(auto &[l, val]: canvas) {
        auto &[r, count] = val;
        if(count > 2) return std::cout << "impossible\n", 0;
        int x = r;
        while(count < 2 && x >= l) try_put(x--);
        if(x < l) return std::cout << "impossible\n", 0;
    }
    std::vector<int> pgs; for(auto p: pegs) if(at.find(p) == at.end()) pgs.push_back(p);
    std::cout << pgs.size() << char(10);
    for(int i = 0; i < pgs.size(); ++i) std::cout << pgs[i] << char(i == pgs.size() - 1 ? 10 : 32);    
    return 0;
}

D. Disposable Switches

挺有意思的一个题

首先可以发现题目中给出的两个参数一起可以统一为一个,即将所有边权整体乘上\(v\)后得到\(l+cv\),将\(cv\)整体看作一个变量

注意到\(cv\)的贡献之和所经过的边数有关,因此考虑在跑最短路的时候把这个信息保留下来

不妨设\(f_{i,j}\)表示从\(1\)号点走到\(i\)号点,恰好经过\(j\)条边的最短路,这个随便DP一下就能求出

假设最后某条\(1\to n\)的最短路恰经过了\(k\)条边,将\(cv\)看作自变量\(x\),\(f_{n,k}\)看作截距,则可以得到一条直线\(y=kx+f_{n,k}\)

不难发现将所有的直线画出来后最后可能称为最短路的就是一个半平面交构成的区域

找出所有在半平面上的直线,倒着还原一遍DP过程即可找出所有的关键点

总复杂度\(O(nm)\)

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#define int long long
#define RI register int
#define CI const int&
#define fi first
#define se second
using namespace std;
typedef pair <int,int> pi;
const int N=2005,INF=1e18;
int n,m,x,y,z,f[N][N],key[N],vis[N][N]; vector <pi> v[N];
inline int Cross(const pi& A,const pi& B,const pi& C)
{
	return (B.fi-A.fi)*(C.se-A.se)-(C.fi-A.fi)*(B.se-A.se);
}
inline void travel(CI now,CI len,CI dis)
{
	if (vis[now][len]) return; vis[now][len]=1;
	key[now]=1; for (auto [pre,w]:v[now])
	if (f[pre][len-1]+w==dis) travel(pre,len-1,f[pre][len-1]);
}
signed main()
{
	RI i,j; for (scanf("%lld%lld",&n,&m),i=1;i<=m;++i)
	scanf("%lld%lld%lld",&x,&y,&z),v[x].push_back(pi(y,z)),v[y].push_back(pi(x,z));
	for (i=1;i<=n;++i) for (j=0;j<=n;++j) f[i][j]=INF;
	for (f[1][0]=0,j=0;j<n;++j) for (i=1;i<=n;++i) if (f[i][j]!=INF)
	for (auto [to,w]:v[i]) f[to][j+1]=min(f[to][j+1],f[i][j]+w);
	vector <pi> stk; for (i=n;i>=1;--i) if (f[n][i]!=INF)
	{
		pi cur=pi(i,f[n][i]);
		while (stk.size()>=2&&Cross(stk[stk.size()-2],stk.back(),cur)>0) stk.pop_back();
		if (stk.size()==1&&stk.back().se>cur.se) stk.pop_back();
		stk.push_back(cur);
	}
	for (auto [len,dis]:stk) travel(n,len,dis);
	vector <int> ans; for (i=1;i<=n;++i) if (!key[i]) ans.push_back(i);
	printf("%lld\n",ans.size()); for (auto x:ans) printf("%lld ",x);
	return 0;
}

E. Expeditious Cubing

徐神开场写的,WA了两发,看来有不少坑点

#include <bits/stdc++.h>

int rd() {
    long double s; std::cin >> s;
    return std::round(s * 100.L);
}

int main() {
    std::vector<int> a(4);
    for(int &a: a) a = rd();
    std::sort(a.begin(), a.end());
    int b = rd() * 3;
    // if(a[0] + a[1] + a[2] >= b) return std::cout << "infinite\n", 0;
    // if(a[1] + a[2] + a[3] < b) return std::cout << "impossible\n", 0;
    int ans = a[0] - 1;
    for(int i = a[3] + 1; i >= a[0]; --i) {
        std::vector<int> c = a; c.push_back(i);
        std::sort(c.begin(), c.end());
        if(c[1] + c[2] + c[3] <= b) { ans = i; break; }
    }
    if(ans == a[0] - 1) return std::cout << "impossible\n", 0;
    if(ans == a[3] + 1) return std::cout << "infinite\n", 0;
    std::cout << ans / 100 << "." << (ans % 100 < 10 ? "0" : "") << ans % 100 << char(10);
    return 0;
}

F. Firetrucks Are Red

祁神开场写的,我题目都没看

#include<bits/stdc++.h>
using namespace std;

const int N = 2e5+5;
int n, fa[N];
int gf(int x){return x==fa[x] ? x : fa[x]=gf(fa[x]);}
map<int, int> mp; int idx=0;
vector<int> G[N];
struct Node{
	int a, b, p;	
};
vector<Node> ans;

signed main(){
	ios::sync_with_stdio(0); cin.tie(0);
	cin >> n;
	idx=0;
	for (int i=1; i<=n; ++i) fa[i]=i;
	for (int i=1; i<=n; ++i){
		int m; cin >> m;
		for (int j=1; j<=m; ++j){
			int a; cin >> a;
			if (!mp.count(a)) mp[a]=++idx;
			G[mp[a]].push_back(i);
		}
	}
	
	for (auto [x, id] : mp){
		int sz=G[id].size();
		for (int j=1; j<sz; ++j){
			if (gf(G[id][j])!=gf(G[id][0])){
				ans.push_back(Node{G[id][j], G[id][0], x});
				fa[gf(G[id][j])] = gf(G[id][0]);
			}
		}
	}	
	bool ok=true;
	for (int i=2; i<=n; ++i) if (gf(i)!=gf(1)){ok=false; break;}
	if (!ok) cout << "impossible\n";
	else{
		for (auto [a, b, p] : ans){
			cout << a << ' ' << b << ' ' << p << '\n';	
		}	
	}
	return 0;
}

G. Gnoll Hypothesis

这题的题意比较鬼畜,我刚开始看错了好几个版本的题意,后面让祁神再读了一遍才搞懂

考虑枚举圆环上两个相邻的选中位置\(x,y(x<y)\),此时\(s'_y=\sum_{i=x+1}^y s_i\),这种局面出现的概率就是\(\frac{C_{n-(y-x+1)}^{k-2}}{C_n^k}\)

注意特判\(k=1\)的情形

#include<bits/stdc++.h>
using namespace std;
using LD = long double;

const int N = 505;
int n, k;
LD sum[N][N];
LD C[N][N];
LD ans[N];
signed main(){
	ios::sync_with_stdio(0); cin.tie(0);
	cout << setiosflags(ios::fixed) << setprecision(10);
	cin >> n >> k;
	
	if (1==k){
		for (int i=0; i<n; ++i) cout << 1.0L/n*100 << ' ';
		cout << '\n';
		return 0;
	}
	
	C[0][0] = C[1][0] = C[1][1] = 1.0L;
	for (int i=2; i<=n; ++i){
		C[i][0] = C[i][i] = 1.0L;
		for (int j=1; j<i; ++j) C[i][j] = C[i-1][j-1] + C[i-1][j];
	}
	
	for (int i=0; i<n; ++i) cin >> sum[i][0];
	for (int j=1; j<n-1; ++j){
		for (int i=0; i<n; ++i){
			sum[i][j] = sum[i][j-1]+sum[(i+n-j)%n][0];	
		}
	}
	
	
	for (int i=0; i<n; ++i){
		for (int x=0; x<=n-k; ++x){
			ans[i] += C[n-x-2][k-2] / C[n][k] * sum[i][x];	
		}
	}	
	for (int i=0; i<n; ++i) cout << ans[i] << ' '; 
	cout << '\n';
	
	return 0;
}

H. Height Profile

这题看数据范围就是允许用\(O(nk\log n)\)的做法的,因此我们考虑对于每个询问分开处理

对于两点\((x_1,y_1),(x_2,y_2)(x_1<x_2)\),需要满足\(\frac{y_2-y_1}{x_2-x_1}\ge g\),移项后得到\(y_2-g\cdot x_2\ge y_1-g\cdot x_1\)

不妨设\(y'=y-g\cdot x\),则原问题等价于找出一段最长的区间\([l,r]\)使得\(y'_r-y'_l\ge 0\)

然后祁神和徐神写了两个version的扫描线,都不知道挂在哪里了,坐等队友补题了


I. Inverted Deck

考虑令\(b\)为排序后的\(a\)数组,原问题等价于要翻转\(b\)的某段区间使其等于\(a\)

找到\(a,b\)两个数组不相同位置的左右端点,翻转这个区间后检验是否相同即可

#include<bits/stdc++.h>
using namespace std;

const int N = 1e6+5;
int n, A[N], B[N];
signed main(){
	ios::sync_with_stdio(0); cin.tie(0);
	cin >> n;
	for (int i=1; i<=n; ++i){
		int a; cin >> a;
		A[i] = B[i] = a;
	}
	sort(B+1, B+n+1);
	int L=-1, R=-1;
	for (int i=1; i<=n; ++i){
		if (A[i]!=B[i]){
			if (-1==L) L=i;
			R=i;
		}
	}
	
	if (-1==L) cout << "1 1\n";
	else{
		bool ok=true;
		for (int i=L; i<=R; ++i){
			if (A[i] != B[L+R-i]){ok=false; break;}	
		}
		if (!ok) cout << "impossible\n";
		else cout << L << ' ' << R << '\n';
	}
	return 0;
}

J. Jackdaws And Crows

很有意思的一个题

考虑如果我们确定了建小号的次数为\(x\),怎么求此时需要删除的帖子数的最小值

不难发现此时可以把所有数分为三类:

  • 无论怎么操作都为正数,记为+
  • 无论怎么操作都为负数,记为-
  • 可以人为操控其正负性,记为?

而对于一段由上述三种字符构成的序列,要求其最少需要删除多少个字符,使得将所有的?赋值后得到一个加减交错的序列

手玩归纳一下会发现一个很好的性质,对于两个相邻的+-,设它们中间有\(t\)个?(可以为\(0\)个),当

  • 相邻的两个符号不同且\(t\)是奇数时,需要删除一个字符
  • 相邻的两个符号相同且\(t\)是偶数时,需要删除一个字符

刚开始想了一堆繁琐的方法来维护这个东西,后面意识到可以从小到大枚举\(x\),此时的操作只有+-变成?

拿一个链表去维护序列中所有的+-,代码十分好写

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<utility>
#define int long long
#define RI register int
#define CI const int&
#define fi first
#define se second
using namespace std;
typedef pair <int,int> pi;
const int N=500005;
int n,c,r,s[N],L[N],R[N],ans,ret; pi p[N];
inline int sgn(CI x)
{
	if (x>0) return 1; if (x<0) return -1; return 0;
}
inline void remove(CI x)
{
	R[L[x]]=R[x]; L[R[x]]=L[x];
}
inline int calc(CI x,CI y)
{
	if (x<1||x>n||y<1||y>n) return 0;
	if (sgn(s[x])!=sgn(s[y])&&(y-x-1)%2==1) return r;
	if (sgn(s[x])==sgn(s[y])&&(y-x-1)%2==0) return r;
	return 0;
}
signed main()
{
	RI i; for (scanf("%lld%lld%lld",&n,&c,&r),i=1;i<=n;++i)
	scanf("%lld",&s[i]),p[i]=pi(abs(s[i]),i);
	int lst=0; for (i=1;i<=n;++i)
	{
		if (!s[i]) { ans+=r; continue; }
		if (lst&&sgn(s[lst])==sgn(s[i])) ans+=r; lst=i;
	}
	for (i=1;i<=n;++i) L[i]=i-1,R[i]=i+1; R[0]=1; L[n+1]=n;
	for (lst=0,i=1;i<=n;++i)
	if (!s[i]) remove(i); else ret+=calc(lst,i),lst=i;
	for (sort(p+1,p+n+1),i=1;i<=n;++i)
	for (ans=min(ans,c+ret),i=1;i<=n;++i) if (p[i].fi)
	{
		auto [val,pos]=p[i]; ret-=calc(L[pos],pos)+calc(pos,R[pos]);
		ret+=calc(L[pos],R[pos]); remove(pos); ans=min(ans,c*(val+1)+ret);
	}
	return printf("%lld",ans),0;
}

K. Kitesurfing

又是防AK题,做不来一点


Postscript

今天状态确实不太好,估计明天要稍微休息一下了的说

标签:std,Northwestern,return,Contest,int,second,2019,include,define
From: https://www.cnblogs.com/cjjsb/p/18006848

相关文章

  • AtCoder Beginner Contest 330
    A-CountingPasses#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongusingvi=vector<int>;usingi32=int32_t;usingpii=pair<int,int>;#definempmake_pairconstintinf=1e9;i32main(){intn,l;......
  • AtCoder Beginner Contest 339
    基本情况A和C出的比较快但不能说秒了还是思考了几分钟的,然后B很奇怪我样例还有一些测试点都能过,但有些测试点就是过不了...A-TLD貌似没啥说的B-Langton'sTakahashi说实话现在还是不懂我的哪里错了很不科学啊,明明很多测试点都过了啊C-PerfectBus做题时的思路:要想求......
  • Japan Registry Services (JPRS) Programming Contest 2024 (AtCoder Beginner Contes
    //这一场我感觉有了新的蜕变思考问题也变了多种,3题(✌)A-TLD思路:题目本意 Youaregivenastring S, Printthelastsubstringwhen S issplitby .s给你一个字符串输出最后的点的网址(类似)的后缀,入坑点没有,题意简单。思路方法:最后一个‘.’为停止符号,倒的字符串......
  • AtCoder Beginner Contest 339
    基本情况ABC秒了,D读错题卡了一段时间,还好爆搜强项,E感觉极其类似LIS,但是似乎又不能用二分DP来写。E感觉极其类似LIS,但是暴力DP肯定T,又知道不能用二分优化事实如此,确实类似LIS,但是通过线段树来维护区间最大值.暂时还没有熟练线段树,先用atc的库来平替.实现上就是将元素依次......
  • Atcoder Beginner Contest 339 解题报告
    AtcoderBeginnerContest339场评:B>C,D>E,F>G,中国选手最擅长的G,集体上分。A-TLDSimulate.strings;voidSolve(){ charc; while(cin>>c) { if(c=='.')s=""; elses+=c; } cout<<s;}B-Langton'sTakahashiSimulat......
  • AtCoder Beginner Contest 339
    A-TLD(abc339A)题目大意给一个网址,问它的后缀是多少。解题思路找到最后的'.'的位置,然后输出后面的字符串即可。python可以一行。神奇的代码print(input().split('.')[-1])B-Langton'sTakahashi(abc339B)题目大意二维网格,上下左右相连,左上原点。初始全部为......
  • 2020-2021 ICPC East Central North America Regional Contest (ECNA 2020)
    Preface队友C麻了我直接3h下班雀魂启动,如果时间多点感觉还有AK希望不过不得不说北美场难度都集中在模拟题上了,一般压轴都是数学或者几何,而这类题目遇到徐神祁神就是洒洒水了A.AllintheFamily出题人真是丧心病狂,不过这题只是看起来恶心实际写起来感觉还好做法本身由于树......
  • AtCoder Beginner Contest 333
    ABC334总结https://atcoder.jp/contests/abc333A-ThreeThrees翻译输入一个正整数\(n\),输出\(n\)遍这个正整数。\(1\len\le9\)。分析没啥好说的,直接输出就好了。code#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;intn;intmain()......
  • [BSidesSF2019]zippy
    [BSidesSF2019]zippy附件是一个流量包追踪TCP流发现压缩密码supercomplexpassword和压缩包通过密码解压后得到flagflag{this_flag_is_your_flag}......
  • 2022-2023 ICPC East Central North America Regional Contest (ECNA 2022)
    Preface闲了两天没训练,今天又开始上班,结果唐得发昏后期也没题可写直接光速下班只能说感觉老外的题目难度跨度都好大,easy确实简单,hard确实难,medium确实少A.A-MazingPuzzle题目看起来很复杂,但仔细一想会发现有用的状态总数只有\(4n^2\)种即我们可以暴力记录下两个机器人的坐......