Codefroces Round 886 Div4 A-H 个人练习

A. To My Critics

A

题目描述:
给定三个整数,判断是否有两个数之和大于等于 10 10 10

思路:
直接选三个数最大的两个数之和判断即可

// Problem: A. To My Critics
// Contest: Codeforces - Codeforces Round 886 (Div. 4)
// URL: https://codeforces.com/contest/1850/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n' 

const int INF=0x3f3f3f3f;
const long long INFLL=0x3f3f3f3f3f3f3f3fLL;

typedef long long ll;

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int t;
    std::cin>>t;
    while(t--){
    	int a,b,c;
    	std::cin>>a>>b>>c;
    	if(a+b+c - std::min({a,b,c}) >= 10)	std::cout<<"YES\n";
    	else std::cout<<"NO\n";
    }
	return 0; 
}

B. Ten Words of Wisdom

B

题目描述:
n n n 个人,每个人说的话有 a i a_i ai 的长度和 b i b_i bi 的价值,规定长度不超过 10 10 10 且价值最高的人是冠军,求出冠军序号

思路:
直接模拟即可

// Problem: B. Ten Words of Wisdom
// Contest: Codeforces - Codeforces Round 886 (Div. 4)
// URL: https://codeforces.com/contest/1850/problem/B
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n' 

const int INF=0x3f3f3f3f;
const long long INFLL=0x3f3f3f3f3f3f3f3fLL;

typedef long long ll;

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int t;
    std::cin>>t;
    while(t--){
    	int n;
    	std::cin>>n;
    	int ans=0;
    	int maxv=0;
    	fore(i,1,n+1){
    		int a,b;
    		std::cin>>a>>b;
    		if(a>10)	continue;
    		if(b>maxv){
    			maxv=b;
    			ans=i;
    		}
    	}
    	std::cout<<ans<<endl;
    }
	return 0; 
}

C. Word on the Paper

C

题目描述:
有一个 8 × 8 8 \times 8 8×8 的网格图,其中有一个竖着的部分是一个单词,要求输出这个单词

思路:
每读入一行,直接输出这一行的字母即可,最后结果就是要求的单词

// Problem: C. Word on the Paper
// Contest: Codeforces - Codeforces Round 886 (Div. 4)
// URL: https://codeforces.com/contest/1850/problem/C
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n' 

const int INF=0x3f3f3f3f;
const long long INFLL=0x3f3f3f3f3f3f3f3fLL;

typedef long long ll;

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int t;
    std::cin>>t;
    while(t--){
    	std::string s;
    	fore(i,0,8){
    		std::cin>>s;
    		for(auto c : s)
    			if(c != '.'){
    				std::cout<<c;
    				break;
    			}
    	}
    	std::cout<<endl;
    }
	return 0; 
}

D. Balanced Round

D

题目描述:
给定 n n n 个题目,每个题目有 a i a_i ai 的难度值,可以执行一下操作:

  • 移走一些元素(或者不移)
  • 重新规划题目的顺序

定义一场比赛是平衡的,当且仅当:

  • 任意两个相邻的题目难度的绝对值之差不超过 k k k ,即: ∀ i ∈ [ 1 , n − 1 ] , ∣ a i − a i + 1 ∣ ≤ k \forall i \in [1,n-1], |a_i - a_{i+1}| \leq k i[1,n1],aiai+1k

为了使这场比赛平衡,求出要移走的最少题目数

思路:
要求移走的最少题目数,也就等价于求要留下的最多题目数
观察可以发现,将一个数组排好序,这样两个相邻元素之间的差值才能最小化

基于这个策略,我们只需要统计符合要求的最大长度即可,其余的部分全部删去

// Problem: D. Balanced Round
// Contest: Codeforces - Codeforces Round 886 (Div. 4)
// URL: https://codeforces.com/contest/1850/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n' 

const int INF=0x3f3f3f3f;
const long long INFLL=0x3f3f3f3f3f3f3f3fLL;

typedef long long ll;

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int t;
    std::cin>>t;
    while(t--){
    	int n,k;
    	std::cin>>n>>k;
    	std::vector<int> v(n);
    	fore(i,0,n)	std::cin>>v[i];
    	std::sort(v.begin(),v.end());
    	int len=1;
    	int idx=1;
    	int l=1;
    	while(idx<n){
    		if(v[idx]-v[idx-1] <= k){
    			++l;
    			len=std::max(len,l);
    		}
    		else{
    			l=1;
    		}
    		++idx;
    	}
    	std::cout<<n-len<<endl;
    }
	return 0; 
}

E. Cardboard for Pictures

E
题目描述:
n n n 个正方形图画,第 i i i 个的边长为 s i s_i si,现在给每一幅画都加一个底片,使得每一幅画的边距离边框都为 w w w

现在给定最后消耗的底片的总面积 c c c,求出 w w w

思路:
其实 c = ∑ i = 1 n ( s i + 2 w ) 2 c = \sum_{i=1}^{n}(s_i + 2w)^2 c=i=1n(si+2w)2,对于一个确定的 w w w,最后消耗的总面积存在单调性
考虑二分,但是要注意不要 l o n g l o n g long long longlong 溢出

// Problem: E. Cardboard for Pictures
// Contest: Codeforces - Codeforces Round 886 (Div. 4)
// URL: https://codeforces.com/contest/1850/problem/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n' 

const int INF=0x3f3f3f3f;
const long long INFLL=0x3f3f3f3f3f3f3f3fLL;

typedef long long ll;

const int N=200050;
ll c;
int n;

ll s[N];

bool check(ll w){
	ll res=0;
	fore(i,1,n+1){
		res+=(s[i]+2ll*w)*(s[i]+2ll*w);
		if(res>c)	return false;
	}
	return res<=c;
}

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int t;
    std::cin>>t;
    while(t--){
    	std::cin>>n>>c;
    	fore(i,1,n+1)	std::cin>>s[i];
    	ll ans=0;
    	ll l=1,r=1e9;
    	while(l<=r){
    		ll mid=l+r>>1;
    		if(check(mid)){
    			ans=mid;
    			l=mid+1;
    		}
    		else r=mid-1;
    	}
    	std::cout<<ans<<endl;
    }
	return 0; 
}

F. We Were Both Children

F

题目描述:
n n n 只青蛙,每只青蛙有 a i a_i ai 的跳跃长度,初始所有青蛙都位于坐标为 0 0 0 的位置
S l a v i c Slavic Slavic 可以在所有青蛙开始跳跃前在某个坐标大于零的位置(但是不能超过坐标 n n n)摆放一个笼子,这个笼子会抓住所有跳到这个位置来的青蛙

最多能抓到多少只青蛙

思路:
这题咋一看好像没有什么思路,能想到的最优的做法就是:枚举每一种青蛙能跳的长度,大于 n n n 的直接忽略,然后更新所有这个长度的青蛙能跳到的位置,这些位置加上能跳这么长的青蛙的数量,可是这样子做的时间复杂度是 O ( n 2 ) O(n^2) O(n2)

其实再仔细观察,时间复杂度其实没有那么高。对于最坏的情况,要枚举 1 → n 1 \rightarrow n 1n 的所有长度,但是对于一个长度 i i i,只需要更新 n i \dfrac {n}{i} in 个位置,时间复杂度其实是: n 1 + n 2 + n 3 + . . . + n n = n ∑ i = 1 n 1 i \dfrac{n}{1} + \dfrac{n}{2} + \dfrac{n}{3} +...+ \dfrac{n}{n} = n \sum_{i=1}^{n}\dfrac{1}{i} 1n+2n+3n+...+nn=ni=1ni1 ,公式求和里面的正是 调和级数!这种复杂度可以称之为 调和级数复杂度

通过程序计算可以得出:在 n = 2 × 1 0 5 n = 2\times10^5 n=2×105 时, ∑ i = 1 n 1 i ≈ 12.7833 \sum_{i=1}^{n}\dfrac{1}{i} \approx 12.7833 i=1ni112.7833,非常小,这样写的时间复杂度是可行的

// Problem: F. We Were Both Children
// Contest: Codeforces - Codeforces Round 886 (Div. 4)
// URL: https://codeforces.com/contest/1850/problem/F
// Memory Limit: 256 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n' 

const int INF=0x3f3f3f3f;
const long long INFLL=0x3f3f3f3f3f3f3f3fLL;

typedef long long ll;

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int t;
    std::cin>>t;
    while(t--){
    	int n;
    	std::cin>>n;
    	std::map<int,int> cnt;
    	std::set<int> s;
    	std::vector<int> v(n+1,0);
    	fore(i,1,n+1){
    		int x;
    		std::cin>>x;
    		s.insert(x);
    		++cnt[x];
    	}
    	for(auto it=s.begin();it!=s.end();++it){
    		int x=*it;
    		int cur=x;
    		while(cur<=n){
    			v[cur] += cnt[x];
    			cur+=x;
    		}
    	}
    	int ans=0;
    	fore(i,1,n+1)	ans=std::max(ans,v[i]);
    	std::cout<<ans<<endl;
    }
	return 0; 
}

G. The Morning Star

G

题目描述:
一个指南针的八个方向如图所示,现在有 n n n 个在二维平面上的点,从这些点里面选择两个点,其中一个放指南针,另外一个放晨星。要求晨星必须在指南针的八个方向之一

问有多少种选择方案?

思路:
其实就是要求选的两个点所确定的直线必须满足以下情况之一:

  • 斜率为 1 1 1
  • 斜率为 − 1 -1 1
  • 斜率为 0 0 0
  • 斜率不存在

对于斜率为 1 1 1 − 1 -1 1 的情况,我们只需要开一个 m a p map map 存这些截距对应的直线上有多少个点即可
对应另外两种情况则分别存 y y y x x x 坐标

最后,对于一种直线上的点,有 2 × c n t × ( c n t − 1 ) 2 \times cnt \times (cnt-1) 2×cnt×(cnt1) 种方案,把这些贡献全部加起来即可

// Problem: G. The Morning Star
// Contest: Codeforces - Codeforces Round 886 (Div. 4)
// URL: https://codeforces.com/contest/1850/problem/G
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n' 

const int INF=0x3f3f3f3f;
const long long INFLL=0x3f3f3f3f3f3f3f3fLL;

typedef long long ll;

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int t;
    std::cin>>t;
    while(t--){
    	int n;
    	std::cin>>n;
    	std::map<int,ll> m1,m2,m3,m4;
    	fore(i,1,n+1){
    		int x,y;
    		std::cin>>x>>y;
    		++m1[y-x]; //斜率为1的直线
    		++m2[y+x]; //斜率为-1的直线
    		++m3[y]; //斜率为0的直线
    		++m4[x]; //斜率不存在的直线
    	}
    	ll ans=0;
    	for(auto it=m1.begin();it!=m1.end();++it){
    		ans+=(it->se)*(it->se-1)/2ll;
    	}
    	for(auto it=m2.begin();it!=m2.end();++it){
    		ans+=(it->se)*(it->se-1)/2ll;
    	}
    	for(auto it=m3.begin();it!=m3.end();++it){
    		ans+=(it->se)*(it->se-1)/2ll;
    	}
    	for(auto it=m4.begin();it!=m4.end();++it){
    		ans+=(it->se)*(it->se-1)/2ll;
    	}
    	std::cout<<(ans<<1)<<endl;
    }
	return 0; 
}

H. The Third Letter

H

题目描述:
现在要设定 n n n 个军营,但是有 m m m 个限制条件: a i a_i ai 号军营必须在 b i b_i bi 号军营的前面距离 d i d_i di 的位置,如果 d i < 0 d_i < 0 di<0,那么就在后面。一个点允许摆放多个军营

回答是否存在一种军营的排列方式符合所有的限制条件

思路:
观察发现,如果 a i a_i ai 号军营在 b i b_i bi 号军营的前面距离 d i d_i di 的位置,那么 b i b_i bi 号军营就在 a i a_i ai 号军营的后面距离 d i d_i di 的位置。考虑图论建模

如果 a i a_i ai 号军营在 b i b_i bi 号军营的前面距离 d i d_i di 的位置,那么我们可以表示为: a → b a \rightarrow b ab 的一条有向边,边权为 d i d_i di,意思就是从 a a a b b b 要向右走 d i d_i di 的距离,还有一条 b → a b \rightarrow a ba 的有向边,边权为 − d i -d_i di,表示从 b b b a a a 要向右走 − d i -d_i di 的距离,也就是向左走 d i d_i di 的距离

这样一来,我们可以很容易地发现:如果不存在排列符合要求的话,一定会出现一些距离间的矛盾,例如:有一条路从 a a a b b b 要走 d 1 d_1 d1 的距离,但是还有一条路从 a a a b b b 要走 y y y 的距离,且 x x x 不等于 y y y ,这就出现了矛盾,这样的限制条件是一定不会被满足的!,所以我们只需要对每个连通块做一次 d f s dfs dfs,确定点之间的距离即可,这里可以使用一个小技巧:用这个连通块里序号最小的点作为根节点,数组 d [ ] d[] d[] 表示这个连通块内所有点到这个序号最小的点的距离,根据图上距离的性质: b → c b \rightarrow c bc 的距离可以用 a → c a \rightarrow c ac 的距离减去 a → b a \rightarrow b ab 的距离来表示,只需检查一次即可

时间复杂度: O ( n + m ) O(n+m) O(n+m)

// Problem: H. The Third Letter
// Contest: Codeforces - Codeforces Round 886 (Div. 4)
// URL: https://codeforces.com/contest/1850/problem/H
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n' 

const int INF=0x3f3f3f3f;
const long long INFLL=0x3f3f3f3f3f3f3f3fLL;

typedef long long ll;

const int N=200050;
std::vector<std::pair<int,int>> edge[N];
ll d[N];

bool dfs(int u,int fa){
	for(auto it:edge[u]){
		int v=it.fi,w=it.se;
		if(!d[v] && v!=fa){
			d[v]=d[u]+1ll*w;
			if(!dfs(v,u))	return false;
		}
		else if(d[v]!=d[u]+1ll*w)	return false;
	}
	return true;
}

bool solve(){
	int n,m;
	std::cin>>n>>m;
	fore(i,1,n+1){
		edge[i].clear();
		d[i]=0;
	}
	fore(i,0,m){
		int u,v,w;
		std::cin>>u>>v>>w;
		edge[u].push_back({v,w});
		edge[v].push_back({u,-w});
	}
	fore(i,1,n+1)
		if(!d[i] && !dfs(i,0))	return false;
	return true;
}

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int t;
    std::cin>>t;
    while(t--){
    	std::cout<<(solve()?"YES":"NO")<<endl;
    }
	return 0; 
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值