终于等到你

众里寻他千百度,蓦然回首,那人却在灯火阑珊处。

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;
}
posted @ 2018-11-30 19:49  gzr2018  阅读(90)  评论(0编辑  收藏  举报