https://codeforces.com/contest/1082
退役了,就写写题解报告过日子了。
A
翻书:给你起点S,终点E,跳动间隔d,可以往前或者往后。但是到边界1或者N时,直接在边界上停止,再继续从边界跳到终点。问需要跳的步数。
1.判断S-E是否可以直接到达(用取余判断)
2.判断S-1-E方式可以成立吗?(用取余判断)
3.判断S-N-E方式可以成立吗?(用取余判断)
4.以上都不成立,-1
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=1e-9;
const int inf=1e9;
const int maxn=1e5;
ll n,x,y,d;
string s;
int cnt=0;
ll num[maxn+5];
int main(){
ll ans=0;
ios::sync_with_stdio(0);
int q;
cin>>q;
while(q--){
cin>>n>>x>>y>>d;
ll ans=0;
if(abs(y-x)%d==0){
ans=abs(y-x)/d;
}
else{
ans=inf;
ll temp1,temp2;
bool ju=false;
if((n-y)%d==0){//hou
temp1=(n-y)/d;
temp1+=(n-x)/d+((n-x)%d>0);
ans=min(ans,temp1);
ju=true;
}
if((y-1)%d==0){//qian
temp2=(y-1)/d;
temp2+=(x-1)/d+((x-1)%d>0);
ans=min(ans,temp2);
ju=true;
}
if(!ju)ans=-1;
}
cout<<ans<<endl;
}
return 0;
}
B
给你一行由G和S组成的字符串,你可以任意调换一下两个位置,问最多的连续的G的长度。
- GG…G | S | GG…G 的情况
- GG…G |SSSSS 的情况
- GG…G | SS…S | GG…G的情况
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=1e-9;
const int inf=1e9;
const int maxn=1e5;
ll n,m,k;
string s;
int cnt=0;
ll num[maxn+5];
int main(){
ll ans=0;
ios::sync_with_stdio(0);
int q;
cin>>q;
cin>>s;
mem(num,0);
cnt=0;
int zheng=0;
for(int i=0;i<q;){
if(s[i]=='G'){
int j=0;
while(s[i+j]=='G'){
num[cnt]++;
j++;
}
i=i+j;
cnt++;
zheng++;
}
else if(s[i]=='S'){
int j=0;
while(s[i+j]=='S'){
num[cnt]--;
j++;
}
i=i+j;
cnt++;
}
}
if(zheng==1){
sort(num,num+cnt);
cout<<max(ans,num[cnt-1])<<endl;
}
else{
for(int i=0;i<cnt;i++){
if(num[i]>0&&num[i+1]==-1&&num[i+2]>0){
if(zheng>2){
ans=max(ans,num[i]+num[i+2]+1);
}
else {
ans=max(ans,num[i]+num[i+2]);
}
}
if(num[i]>0)ans=max(ans,num[i]+1);
}
cout<<ans<<endl;
}
return 0;
}
C
给你n个人,他有值为k(可负)的技能m。需要你寻找一个答案,使得不同技能的人数一样多(技能可以不用全选)但是你需要找一个最大的k的和。
肯定一开始都是想贪心暴力,能理解,但是这题有可能T,队友题解给的是队列优化,但是我自己写的是暴力剪枝。
注意:
1.每个技能排序完之后,前缀和求一下,得到不同人数下的值,这里就可以把前缀和小于0的全舍去。
2.对不同技能的前缀和,存一个人数的前缀和:如果这个技能在当下的人数的前缀和依然大于0,那么就可以加入当下的人数的前缀和里
3. 每一次更新前缀和,都找和的最大值。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=1e-9;
const int inf=1e9;
const int maxn=1e5;
ll n,m,d;
vector<ll>num[maxn+5];
int siz[maxn+5];
bool cmp(ll a,ll b){
return a>b;
}
ll ans=0;
ll summ[maxn+5];
int main(){
ios::sync_with_stdio(0);
int a;
ll b;
cin>>n>>m;
for(int i=0;i<n;i++){
cin>>a>>b;
num[a].push_back(b);
}
int sizz=0;
mem(summ,0);
ans=0;
for(int i=1;i<=m;i++){
siz[i]=num[i].size();
if(siz[i]<=0)continue;
sort(num[i].begin(),num[i].end(),cmp);
if(num[i][0]>0){
summ[0]+=num[i][0];
ans=max(ans,summ[0]);
}
for(int j=1;j<siz[i];j++){
if(num[i][j-1]+num[i][j]>0){
num[i][j]=num[i][j-1]+num[i][j];
summ[j]+=num[i][j];
ans=max(ans,summ[j]);
}
else {
break;
}
}
}
cout<<ans<<endl;
return 0;
}
下面是队友的队列写法
#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
找一颗树,最大度数固定,问能否构成,若可以,找树有最长的直径的构造方式。
找主链,然后填入叶子,具体看看CF官方题解吧!
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=1e-9;
const int inf=1e9;
const int maxn=500;
int a[maxn+10];
int main(){
int n,m;
cin>>n;
ll sum=0;
vector<int>ones;
for(int i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
if(a[i]==1){
ones.push_back(i);
a[i]=0;
}
}
if(sum<2LL*n-2)cout<<"NO\n";
else{
int onesize=ones.size();
int len=(n-onesize)-1+min(2,onesize);//数的直径长度
cout<<"YES "<<len<<"\n"<<n-1<<"\n";
int edg=n-1;
int lst=-1;
if(!ones.empty()){//主链找一个头节点
lst=ones.back();
ones.pop_back();
}
for(int i=1;i<=n;i++){
if(a[i]>1){
if(lst!=-1){//有头节点
a[lst]--;
a[i]--;
cout<<lst<<" "<<i<<endl;
}//形成主链
lst=i;
}
}
for(int i=n;i>=1;i--){//填上叶子节点
while(!ones.empty()&&a[i]>0){
a[i]--;
cout<<i<<" "<<ones.back()<<endl;
ones.pop_back();
}
}
}
return 0;
}