A. Vasya and Book
分情况讨论,当x大于y的时,交换x,y是错误的!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
int t;
int n,d,x,y;
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d%d%d%d",&n,&x,&y,&d);
int t=abs(x-y);
if(t%d==0)printf("%d\n",t/d);
else if(y==1)printf("%d\n",(x-2)/d+1);
else if(y==n)printf("%d\n",(y-x-1)/d+1);
else {
int ans=inf;
if((y-1)%d==0)ans=min(ans,(y-1)/d+(x-2)/d+1);
if((n-y)%d==0)ans=min(ans,(n-y)/d+(n-x-1)/d+1);
printf("%d\n",ans!=inf?ans:-1);
}
}
return 0;
}
B. Vova and Trophies
统计出有num个G串,第i个G串的数量为cnt[i]。
第i个G串能否和下一个G串链接,用can[i]表示。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Max_n=1e5+10;
int n;
char s[Max_n];
int cnt[Max_n];
bool can[Max_n];
int main()
{
scanf("%d%s",&n,s);
int num=0;
memset(cnt,0,sizeof(cnt));
memset(can,0,sizeof(can));
for(int i=0;i<n;i++){
if(s[i]=='G'){
if(i>0&&s[i-1]=='G')cnt[num]++;
else cnt[++num]++;
}
else {
if(i>0&&i<n-1&&s[i-1]=='G'&&s[i+1]=='G')
can[num]=true;
}
}
int Max=0;
for(int i=1;i<=num;i++){
if(can[i]){
if(i>1||i+1<num)Max=max(Max,cnt[i]+cnt[i+1]+1);
else Max=max(Max,cnt[i]+cnt[i+1]);
}
else {
if(i>1||i<num)Max=max(Max,cnt[i]+1);
else Max=max(Max,cnt[i]);
}
}
printf("%d\n",Max);
return 0;
}
// 另附录网上大佬代码,膜拜!
#include<bits/stdc++.h>
using namespace std;
int main(){
int n; string s;
//freopen("in.txt","r",stdin);
while(cin>>n){
cin>>s;
int cntG=0,cntS=0,sumG=0,ans=0;
for(int i=0;i<n;i++){
if(s[i]=='G'){
cntG++; sumG++;
}
else{
cntS=cntG; cntG=0;//遇到scntG从新归零统计G连续的个数
}
ans=max(ans,cntG+cntS+1);//假设都可以交换带来收益
}
ans=min(ans,sumG);//这里很关键存在交换没有带来收益的
cout<<ans<<endl;
}
return 0;
}
C. Multi-Subject Competition
先以选科目总数降序排序,其次以科目升序排序,最后以能力水平降序排序。
然后两层for循环暴力枚举。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Max_n=1e5+10;
int n,m;
struct node{
int s,r,k; //k代表选s科目的总人数
bool operator<(const node &n)const {
if(k!=n.k)return k>n.k;
if(s!=n.s)return s<n.s;
return r>n.r;
}
}no[Max_n];
int sum[Max_n]; //前缀和
int cnt[Max_n]; //第i个科目的人数
int main()
{
scanf("%d%d",&n,&m);
memset(cnt,0,sizeof(cnt));
no[0].s=no[0].r=0;no[0].k=Max_n;
for(int i=1;i<=n;i++){
scanf("%d%d",&no[i].s,&no[i].r);
cnt[no[i].s]++;
}
for(int i=1;i<=n;i++){
no[i].k=cnt[no[i].s];
}
sort(no,no+n+1);
//for(int i=0;i<=n;i++)cout<<no[i].s<<' '<<no[i].r<<' '<<no[i].k<<endl;
for(int i=1;i<=n;i++){
sum[i]+=sum[i-1]+no[i].r;
}
int Max=0;
for(int i=1;i<=n;i++){ //最多n个人同时选一个科目
int ans=0;
for(int j=1;j<=n;j+=no[j].k){
if(no[j].k<i)break; //选第no[j].s科目人数小于i
if(sum[j+i-1]-sum[j-1]>0)
ans+=sum[j+i-1]-sum[j-1];
}
if(ans>Max)Max=ans;
}
printf("%d\n",Max);
return 0;
}
// 另附网上大佬代码,膜拜!
首先,读入后,把每一个分数扔进相应学科的桶。
然后贪心地对每个桶排序。
然后对于每一个桶,求前缀和,如果大于0,就加到对应的sum[i]中(sum[i]记录的是每个学科i个人的最大得分)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int Max_n=1e5+10;
int n,m;
int sum[Max_n];
vector<int>v[Max_n];
int main()
{
scanf("%d%d",&n,&m);
int a,b;
for(int i=1;i<=n;i++){
scanf("%d%d",&a,&b);
v[a].push_back(b);
}
memset(sum,0,sizeof(sum));
for(int i=1;i<=m;i++){
sort(v[i].begin(),v[i].end(),greater<int>());
int tmp=0;
for(int j=0;j<v[i].size();j++){
tmp+=v[i][j];
if(tmp<0)break;
sum[j+1]+=tmp;
}
}
int Max=0;
for(int i=1;i<=n;i++){
Max=max(sum[i],Max);
}
printf("%d\n",Max);
return 0;
}
D. Maximum Diameter Graph
写了很久,感觉思路蛮对的,一直WA18…看了好几天,终于A了,开心!
定义: 1. 主干长度:所有入度>1的顶点数排成一排。 2. 入度为1的点为叶子。
最长路径=主干长度+是否能在主干两端各加一个叶子(想一想,很简单的)
// 输出路径时,先输出主干路径,再在两端各加一个叶子达到最长(可以的话),最后,剩余的叶子随意加到主干上就好。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Max_n=5500;
int n;
int s[Max_n];
int x=0,a[Max_n]; //入度>1顶点数
int y=0,b[Max_n]; //入度=1顶点数
int main()
{
scanf("%d",&n);
int sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&s[i]);
if(s[i]>1){sum+=s[i];a[x++]=i;}
else b[y++]=i;
}
//判断输出YES条件:sum-(x-1)*2>=y
//最长路径=主干长度(所有入度>1顶点数)+是否能在主干两端各加一个叶子
if(sum-(x-1)*2>=y)printf("YES %d\n%d\n",x-1+(y>1?2:y),n-1);
else {printf("NO\n");return 0;}
//输出主干路径
for(int i=1;i<x;i++)
printf("%d %d\n",a[i-1],a[i]);
if(y>=1)printf("%d %d\n",b[0],a[0]); //必须先在主干两端加叶子!
if(y>=2)printf("%d %d\n",b[1],a[x-1]);
//剩下的入度=1顶点数随意加在主干上
int i=2,j=0;
while(i<y){
if(s[a[j]]>2){
printf("%d %d\n",b[i],a[j]);
s[a[j]]--;i++;
}
else j++;
}
return 0;
}
// 附上自测样例:
8
4 2 3 1 1 1 1 1
YES 4
7
1 2
2 3
4 1
5 3
6 1
7 1
8 3
5
4 2 3 1 1
YES 4
4
1 2
2 3
4 1
5 3
4
4 2 3 1
YES 3
3
1 2
2 3
4 1