Educational Codeforces Round 55 (Rated for Div. 2)
题目链接A~D
A. Vasya and Book
题意:起点为page x,问到终点page y至少需要几步,给出步长为d,可以向左向右移动d步,移动范围为1~n,当步长越界时,最多到1或者n(如果当前为2,步长为2,向左可以到1,向右可以到3),如果不能达到y,输出-1。
tips:
- 可以用(dis-1)/d+1来判断移动到1需要几步。
- 这个题需要注意y不一定比x小。
- 如果可以整除,即直接x到y,否则求是否可以借助1或者n到y,都求出来去最小即可。
#include<bits/stdc++.h>
using namespace std;
const int INF=1000000000;
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int n,x,y,d;
int t;
cin>>t;
while(t--)
{
cin>>n>>x>>y>>d;
int ans=INF;
if(abs(y-x)%d==0)cout<<abs(y-x)/d<<endl;
else
{
if((y-1)%d==0) ans=min(ans,(x-1-1)/d+1+(y-1)/d);
if((n-y)%d==0)ans=min(ans,(n-x-1)/d+1+(n-y)/d);
if(ans==INF)cout<<-1<<endl;
else cout<<ans<<endl;
}
}
return 0;
}
B. Vova and Trophies
题意:给出仅仅由G或S组成的字符串,最多交换一次两个字母的位置,求最长连续的G的字符串长度
tips:
- 注意这个题是交换,不是更换一个字母
- pre表示之前连续的G的长度,cur表示当前连续的G的长度。注意当前范访问的不是G则把cur赋给pre,cur变为0,更新结果ans=max(ans,pre+cur+1),巧妙用到一个S的情况,如果遇到连续的S,cur变为0。不断更新ans。
- 然后最大的ans不能超过ng(G的数目)。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int n;string s;
cin>>n>>s;
int ans=0;
int cur=0;int ng=0;int pre=0;
for(int i=0;i<n;i++){
if(s[i]=='G'){
cur++;ng++;
}
else {
pre=cur;
cur=0;
}
ans=max(ans,pre+cur+1);
}
cout<<min(ans,ng)<<endl;
return 0;
}
C. Multi-Subject Competition
题意:m个科目,教练可以选择一些科目去参加比赛,必须保证没门科目参加的人数一样,每个学生有某一门科目的能力值,但可以为负数,教练要使得参加比赛的同学的能力值总和最大,求最大的能力值,如果最大能力值为负,则输出0.
tips:
- 对于输入可以采用二维vector,即每一门科目保存在一条链中,然后从大到小排序。 sort(v[i].rbegin(),v[i].rend());
- 然后枚举参加比赛的人数,1~m,保存到一个数组中记录全部的值
- *max_element(ans,ans+N)运用这个求数组最大值,判断是否大于0
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
#define long long ll
vector<int>v[N];
int ans[N];
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int n,m;
int x,y;
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>x>>y;
v[x].push_back(y);
}
for(int i=1;i<=m;i++)
sort(v[i].rbegin(),v[i].rend());
for(int i=1;i<=m;i++)
{
int sum=0;
for(int j=0;j<v[i].size();j++)
{
sum+=v[i][j];
ans[j]+=max(sum,0);
}
}
if(*max_element(ans,ans+N)<0)cout<<0<<endl;
else cout<<*max_element(ans,ans+N)<<endl;
return 0;
}
D. Maximum Diameter Graph
题意:给出每个结点最大连接的边数,判断是否可以组成一个连接的图,如果可以,使得数的直径(the maximum number of edges in the shortest path between any pair of its vertices.)最大,输出直径,然后输出每一条边左右结点编号。
tips:
- 图的直径最大,即是的度大于等于2的结点一条连接,然后是的度为1的结点连在边界或者度大于2的结点上。
- 如果num(总的度数)<2*n-2,无法成图。直径为min(n-1,n+1-sum)(sum为度为1的结点数目)
- 贪心法即可,细节处理可以看一下代码,输出满足当前能满足的。
#include <iostream>
using namespace std;
int a[550];
int n;
int main()
{
cin>>n;
int sum=0,num=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
num+=a[i];
sum+=a[i]==1;
}
if(num<2*n-2){cout<<"NO"<<endl;return 0;}
cout<<"YES"<<" "<<min(n-1,n+1-sum)<<endl;
cout<<n-1<<endl;
int cur=0;
for(int i=1;i<=n;i++)
{
if(a[i]>1){
if(cur)cout<<cur<<" "<<i<<endl;
else a[i]++;//边界,可以视为他的度+1
cur=i;
}
}
int k=1;
for(int i=1;i<=n;i++){
if(a[i]==1){
if(cur){cout<<cur<<" "<<i<<endl;cur=0;continue;}//首先连接在最后一位
for(;a[k]<=2;k++);
cout<<i<<" "<<k<<endl;
a[k]--;
}
}
return 0;
}
不疯魔不成活