概述
A题 A. AvtoBus
题意分析
- 有n个轮子,分别是4轮车和6轮车上的,问最少和最多有多少辆车?如果不合法,输出-1
思路分析
- 奇数的情况肯定是不合法的,输出-1.
- 然后,我们需要知道
4
x
+
6
y
=
n
4x+6y=n
4x+6y=n,我们需要想办法最大化和最小化x+y。分情况讨论。
- 最小化的时候,肯定是优先满足六轮车, n u m 1 = n 6 num1=frac{n}{6} num1=6n,剩下 m = n − 6 n u m 1 m=n-6num1 m=n−6num1,那么此时四轮车 m 4 frac{m}{4} 4m辆,为如果m除以4此时有余数,肯定是2,那么我们只需要把6辆的车减少一辆,和这个2合并成两辆四轮车。
- 最大化的时候,肯定是优先满足四轮车, n u m 1 = n 4 num1=frac{n}{4} num1=4n,剩下的就是 m = n − 4 ∗ n u m 1 m=n-4*num1 m=n−4∗num1,如果此时有m除以6有余数,肯定是2,所以我们从四轮车里面拿出一辆和2拼接成一个六轮车就行了。
代码
// Problem: A. AvtoBus
// Contest: Codeforces - Codeforces Round #791 (Div. 2)
// URL: https://codeforces.com/contest/1679/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve(){
ll n;
cin>>n;
if(n&1||n<=2){
puts("-1");
}else{
ll ans1=n/6;
ll now=n-6*ans1;
if(now==2){
ans1--;
now+=6;
}
ans1+=now/4;
ll ans2=n/4;
now=n-4*ans2;
if(now==2){
ans2--;
now+=4;
}
ans2+=now/6;
cout<<ans1<<" "<<ans2<<endl;
}
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
B题 Stone Age Problem
题意分析
- 给出一个数组,两种操作。
- 替换第 i i i个位置的数为 x x x
- 将数组的所有数都替换成 x x x
- 我们需要计算每次操作之后的数组的和,注意,操作之间是相互干扰的,也就是后面一次的操作都是在前面一次的操作的基础上实现的。
思路分析
- 我们给每个位置维护一个
v
e
r
s
i
o
n
version
version版本号,同时用一个
n
v
nv
nv来维护全局修改的版本号。
- 如果是第一种操作,先比较这个位置的版本号是否是小于最新的全局修改的版本号,如果小于,那么就将这个位置的版本号和当前最新的全局修改版本号 n v nv nv同步,注意需要更新这个位置的数字。如果大于等于,那么执行正常的替换操作。
- 如果是第二种操作,那么我们直接更新全局修改的版本号即可,注意此时没有必要更新每个位置的值。因为全局更新带来的问题我们可以使用一个 n v nv nv版本号和 n o w now now来维护。
代码
// Problem: B. Stone Age Problem
// Contest: Codeforces - Codeforces Round #791 (Div. 2)
// URL: https://codeforces.com/contest/1679/problem/B
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[200010];
int tag[200010];
void solve(){
memset(tag,0,sizeof(tag));
int n,q;
scanf("%d %d",&n,&q);
ll sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum+=a[i];
tag[i]=0;
}
int nv=0;
ll now;
while(q--){
int t;
scanf("%d",&t);
if(t==1){
int i,x;
scanf("%d %d",&i,&x);
if(tag[i]<nv){
tag[i]=nv;
sum-=now;sum+=x;
a[i]=x;
}else{
sum-=a[i];sum+=x;a[i]=x;
}
}else{
ll x;
scanf("%lld",&x);
now=x;
nv++;
sum=x*n;
}
printf("%lldn",sum);
}
}
int main(){
int t;
//scanf("%d",&t);
t=1;
while(t--){
solve();
}
return 0;
}
C题 C. Rooks Defenders
题意分析
- 给出一个棋盘,可以在某一个位置放置一个车,同时可以拿走某一个位置的车(保证这个位置一定有车)。多次询问某一个矩阵的所有的位置是否可以被至少一个车到达。如果有,输出
YES
,否则输出NO
- 注意这里的车是可以横向水平移动和纵向垂直移动的。
思路分析
- 我们观察到,如果想要一个矩阵的每个位置都必须被至少一个车到达,有两种情况,一种是这个矩阵的所有的行都至少有一个车,或者是这个矩阵的所有的列都至少有一个车。两个只需要满足一种情况,这个矩阵就是可完全覆盖的。
- 所以,行和列分开讨论。对于行或者是列,我们需要维护一个区间的区间和,这个区间和就是这个区间内有多个车,表示的是有多少行或者是多少列被覆盖了。对于放置车或者是拿走车的操作,其实就是类似于单点修改,不过我们要从行和列两个维护同时维护就是了。
- 问题抽象出来最后就是维护两个树状数组,分别是行和列,然后就是一个很简单的单点修改和区间查询了。
代码
// Problem: C. Rooks Defenders
// Contest: Codeforces - Codeforces Round #791 (Div. 2)
// URL: https://codeforces.com/contest/1679/problem/C
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
int hang[N],lie[N];
int c1[N],c2[N];
// 维护x坐标
void add1(int x,int k){
for(;x<N;x+=x&(-x)){
c1[x]+=k;
}
}
int query1(int x){
int sum=0;
for(;x;x-=x&(-x)){
sum+=c1[x];
}
return sum;
}
// 维护y坐标
void add2(int x,int k){
for(;x<N;x+=x&(-x)){
c2[x]+=k;
}
}
int query2(int x){
int sum=0;
for(;x;x-=x&(-x)){
sum+=c2[x];
}
return sum;
}
void solve(){
memset(hang,0,sizeof(hang));
memset(lie,0,sizeof(lie));
int n,q;
scanf("%d %d",&n,&q);
while(q--){
int t;
int x,y;
int a,b,c,d;
scanf("%d",&t);
if(t==1){
scanf("%d %d",&x,&y);
if(hang[x]==0){
add1(x,1);
}
hang[x]++;
if(lie[y]==0){
add2(y,1);
}
lie[y]++;
}else if(t==2){
scanf("%d %d",&x,&y);
hang[x]--,lie[y]--;
if(hang[x]==0){
add1(x,-1);
}
if(lie[y]==0){
add2(y,-1);
}
}else{
scanf("%d %d %d %d",&a,&b,&c,&d);
int sum1=query1(c)-query1(a-1);
int sum2=query2(d)-query2(b-1);
if(sum1==c-a+1||sum2==d-b+1){
puts("Yes");
}else{
puts("No");
}
}
}
}
int main(){
int t;
//scanf("%d",&t);
t=1;
while(t--){
solve();
}
return 0;
}
D题 Toss a Coin to Your Graph…
题意分析
- 给出一个图,对于所有路径长度为k的路径,我们需要让路径的最大值最小化。没有的话输出-1.
思路分析
- 最大值最小化,一般都是二分的解法。我们发现,最后的答案有二分性。所以我们二分最后的答案,然后进行判断。
- 注意,这里我们判断的时候,如果这个结点的权值大于我们二分的值,显然是不符合要求的。所以我们需要过滤掉所有的权值大于二分的值的情况。然后对于剩下的图,如果有环,那么肯定是符合要求的,如果没有,我们可以维护过滤之后的最长路径,如果不小于 k k k,那么也是符合要求的。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200010;
vector<int> v[N];
int a[N];
int cnt[N];
ll dp[N];
int n,m;
ll k;
bool cycle;
ll dfs(int x,int sum){
if(a[x]>sum) return 0;
// 如果遇到标记为1的,说明成环了
if(cnt[x]==1) return k;
if(cnt[x]==2) return dp[x];
dp[x]=1;cnt[x]=1;
for(auto y:v[x]){
dp[x]=max(dp[x],dfs(y,sum)+1);
}
// 当这个循环走到了底,就将他标记为2
cnt[x]=2;
return dp[x];
}
bool judge(int x){
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++){
if(!cnt[i]){
// 如果这个结点没有被访问过
if(dfs(i,x)>=k){
return true;
}
}
}
return false;
}
int main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
v[x].push_back(y);
}
int ans=1e9+7;
int l=1,r=1e9,mid;
while(l<=r){
mid=(l+r+1)>>1;
//cout<<l<<" "<<r<<endl;
if(judge(mid)){
ans=mid;
r=mid-1;
}else{
l=mid+1;
}
}
if(ans==1e9+7) ans=-1;
cout<<ans<<endl;
return 0;
}
最后
以上就是快乐期待为你收集整理的Codeforces Round #791 (Div. 2)题解的全部内容,希望文章能够帮你解决Codeforces Round #791 (Div. 2)题解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复