A题:
题意:从x到y翻书,每次只能翻d页,翻页的上下限为1和n,能翻到输出最小的步数,不能输出-1
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <map>
#include <vector>
#include <set>
#include <queue>
#define ll long long
using namespace std;
int main()
{
ios::sync_with_stdio(false);
int t;
int n,x,y,d;
cin>>t;
while(t--)
{
ll minn=0x3f3f3f3f3f3f3f3f;
cin>>n>>x>>y>>d;
if(abs(y-x)%d==0)
{
cout<<abs(y-x)/d<<endl;
continue;
}
if((y-1)%d==0)
{
ll now=(y-1)/d;
ll tem=(x-1)/d+1;
if((x-1)%d==0)tem--;
now+=tem;
minn=min(minn,now);
}
if((n-y)%d==0)
{
ll now=(n-y)/d;
ll tem=(n-x)/d+1;
if((n-x)%d==0)tem--;
now+=tem;
minn=min(minn,now);
}
if(minn!=0x3f3f3f3f3f3f3f3f)
{
cout<<minn<<endl;
}
else
{
cout<<-1<<endl;
}
}
return 0;
}
B题:
题意:求交换一次的最长G的长度
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <map>
#include <vector>
#include <set>
#include <queue>
#define ll long long
using namespace std;
map<int,int>m;
struct node
{
ll fir,sec;
}nod[100005];
int main()
{
int n,num=0;
cin>>n;
string s;
cin>>s;
for(int i=0;i<s.size();i++)
{
if(s[i]=='G')
{
int j=i+1;
while(s[j]=='G'&&j<s.size())
{
j++;
}
nod[++num].fir=i;
nod[num].sec=j-1;
i=j;
}
}
//cout<<nod[1].fir<<' '<<nod[1].sec<<" "<<nod[2].fir<<' '<<nod[2].sec<<endl;
//cout<<num<<endl;
ll now;
ll ans=0;
if(num==0)cout<<0<<endl;
else if(num==1)cout<<nod[1].sec-nod[1].fir+1<<endl;
else if(num>=2)
{
for(int i=2;i<=num;i++)
{
if(nod[i].fir-nod[i-1].sec==2)
{
now=nod[i].sec-nod[i-1].fir+1;
if(num==2)
{
now--;
}
ans=max(ans,now);
}
else
{
ans=max(ans,max((nod[i].sec-nod[i].fir)+2,(nod[i-1].sec-nod[i-1].fir)+2));
}
}
cout<<ans<<endl;
}
return 0;
}
C题:
题意:有n个人和m个项目,第i个人对第a[i]个项目有b[i]的贡献,可以为负,现在教练挑选候选人参加项目,所选的项目参加人数必须相同,可以不选。问最后的总收益最大值。
对于第i个项目不取的情况有两种:1.人数不够 2.最大贡献为负
思路:前缀和打表。sum[i]表示所选的项目有i个人参加的最大收益
对于每个项目记录所有贡献,从大到小排序之后,每次取i个最大的相加,一旦大于0,就放入总的sum[i]中。
#include <algorithm>
#include <vector>
#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
const int N=1e5+2;
priority_queue<int,vector<int> ,less<int> >q[100005];
ll sum[100005];//表示sum[i]表示有i个人参加单个项目的最大收益
int main()
{
int tem1,tem2;
ios::sync_with_stdio(false);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>tem1>>tem2;
q[tem1].push(tem2);
}
ll now=0,cnt=0,res=0;
for(int i=1;i<=m;i++)
{
now=0;cnt=0;
while(!q[i].empty())
{
now+=q[i].top();
if(now>0)
{
sum[cnt++]+=now;
}
q[i].pop();
}
}
for(int i=0;i<n;i++)
{
res=max(res,sum[i]);
}
cout<<res<<endl;
return 0;
}
D题:
构造,无向树,共有n个节点,输入每个节点最大的度,记为这个树上第和第两个节点的距离,如果这个树存在,输出让L的最大值 最大的方案的边的构造方法和长度。
感觉思路挺好想的,要让最长链尽量长,这个树的形态肯定是一根很长的单链+叶节点。实现就emmm
先从这里面选出度数最小的两个节点作为主链的头尾节点,度数大于等于2的节点作为主链,所有最大度数为1的节点直接连在这个主链上。
实现上我的思路是先一个扣一个的把主链先构造出来放到一个vector里面存着,然后再加叶节点。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
#define PIR pair<int,int>
struct node
{
int id;
int num;
}a[505];
bool cmp(node a,node b)
{
return a.num<b.num;
}
using namespace std;
int main()
{
vector<PIR>v;
vector<int>vv;//记录叶节点的id
int n;
int tem;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>tem;
a[i].id=i;
a[i].num=tem;
}
sort(a+1,a+n+1,cmp);
int sta=a[1].id;
int end=a[2].id;
int sum=0;
int sta_2=0;
int size;
for(int i=3;i<=n;i++)//先构造主链
{
if(a[i].num==1)
{
vv.push_back(a[i].id);
}
else
{
if(sta_2==0)
{
sta_2=i;
}
sum+=a[i].num-2;
v.push_back(make_pair(sta,a[i].id));
sta=a[i].id;
}
}
v.push_back(make_pair(sta,end));
size=v.size();
int cnt=0;
//需要进行配对的1是从3~sta_2-1
for(int i=sta_2;i<=n&&cnt<vv.size();i++)
{
if(a[i].num>2)
{
while(a[i].num>2&&cnt<vv.size())
{
a[i].num--;
v.push_back(make_pair(vv[cnt++], a[i].id));
}
}
if(cnt>=vv.size())//1已经用完了
{
cout<<"YES "<<size<<endl;
cout<<v.size()<<endl;
for(int j=0;j<v.size();j++)
{
cout<<v[j].first<<' '<<v[j].second<<endl;
}
return 0;
}
else
{
if(i==n&&cnt<vv.size())//大于等于2的已经用光了并且1还没填完
{
cout<<"NO"<<endl;
return 0;
}
continue;
}
}
cout<<"YES "<<size<<endl;
cout<<v.size()<<endl;
for(int j=0;j<v.size();j++)
{
cout<<v[j].first<<' '<<v[j].second<<endl;
}
return 0;
}