A. To My Critics
题目描述:
给定三个整数,判断是否有两个数之和大于等于
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
题目描述:
有
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
题目描述:
有一个
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
题目描述:
给定
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,n−1],∣ai−ai+1∣≤k
为了使这场比赛平衡,求出要移走的最少题目数
思路:
要求移走的最少题目数,也就等价于求要留下的最多题目数
观察可以发现,将一个数组排好序,这样两个相邻元素之间的差值才能最小化
基于这个策略,我们只需要统计符合要求的最大长度即可,其余的部分全部删去
// 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
题目描述:
有
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
题目描述:
有
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 1→n 的所有长度,但是对于一个长度 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=n∑i=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=1ni1≈12.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
题目描述:
一个指南针的八个方向如图所示,现在有
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×(cnt−1) 种方案,把这些贡献全部加起来即可
// 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
题目描述:
现在要设定
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 a→b 的一条有向边,边权为 d i d_i di,意思就是从 a a a 到 b b b 要向右走 d i d_i di 的距离,还有一条 b → a b \rightarrow a b→a 的有向边,边权为 − 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 b→c 的距离可以用 a → c a \rightarrow c a→c 的距离减去 a → b a \rightarrow b a→b 的距离来表示,只需检查一次即可
时间复杂度: 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;
}