CF965

A

直接按照1,2,3这样下去一直构造即可。

需要考虑可能重叠的情况,所以需要特判修改一下\(x_k,y_k\)

(这个地方一开是写错了,被罚惨了)。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
void solve()
{
int xc,yc,k; cin>>xc>>yc>>k;
int sx=xc*k,sy=yc*k;
std::vector<int> vx(k+1,0);
std::vector<int> vy(k+1,0);
int sumx=0,sumy=0;
if(k==1)
{
cout<<xc<<" "<<yc<<"\n";
return;
}
for(int i=1;i<=k;i++)
{
if(i==k) vx[i]=sx-sumx,vy[i]=sy-sumy;
else vx[i]=i,sumx+=i,vy[i]=i,sumy+=i;
}
if(vx[k]==vy[k] && vx[k]<k && vx[k]>=1)
{
vx[1]-=vx[k],vx[k]*=2;
vy[1]-=vy[k],vy[k]*=2;
}
for(int i=1;i<=k;i++)
{
cout<<vx[i]<<" "<<vy[i]<<"\n";
}
}
int main()
{
int t=1;
cin>>t;
while(t--) solve();
return 0;
}

B

不难想到:对每一个数加1,然后最大的减去\(n-1\)即可。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
void solve()
{
int n; cin>>n;
std::vector<int> v(n,0);
int maxn=0;
for(auto &t: v) cin>>t,maxn=max(maxn,t);
for(auto &t: v)
{
if(t==maxn) cout<<1<<" ";
else cout<<t+1<<" ";
}
cout<<"\n";
}
int main()
{
int t=1;
cin>>t;
while(t--) solve();
return 0;
}

C

可以发现,如果对中位数\(midian(c_i)\)进行修改,那么效果肯定是不如对\(a_i\)进行修改的。(因为修改\(median(c_i)\)的效率是小于等于1)。所以我们可以分类讨论一下:

  • 如果\(a_i\)可以修改,那么我们直接把全部的修改次数用到\(a_i\)
  • 否则,对\(median(c_i)\)进行修改,尽可能使得其更大。

第一种情况:枚举每一个可以修改的\(a_i\),并且进行计算,选取最大值。

第二种情况:要找一个中位数(或者百分位数),常用的一个技巧是用二分,

我们二分要找的中位数数的值,那么在整个数列中,肯定有一半及以上的数字是超过中位数,我们可以计算满足的个数,然后来判断我们目前二分的这个值是否合法。

\(check\)函数:可以先记录大于等于\(x\)的个数(记作\(cnt\)),然后再寻找那些可以修改的,并且小于\(x\)的数,计算需要的贡献\(need\),如果中间\(need>k\),那么\(x\)不合法,直接退出。否则最后判断\(cnt\)是否大于数组的一半大小。

还需要考虑的一点就是:\(a_i\)的位置,会对\(median(c_i)\)的位置产生影响。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
void solve()
{
int n; cin>>n;
ll k; cin>>k;
std::vector<pair<ll,bool>> a(n,{0,0});
for(auto &t: a) cin>>t.first;
for(auto &t: a) cin>>t.second;
sort(a.begin(),a.end(),[&](pair<ll,bool> a, pair<ll,bool> b){ return a.first<b.first; });
//情况1 直接选取可以修改的a
ll ans=0;
for(int i=0;i<n;i++)
{
if(a[i].second)
{
if(i<n/2) ans=max(ans,k+a[i].first+a[n/2].first);
else ans=max(ans,k+a[i].first+a[n/2-1].first);
}
}
//情况2 a不可以修改,二分查找中位数
auto check=[&](ll x,int p)->bool
{
int cnt=0;
for(int i=n-1;i>=0;i--)
{
if(a[i].first>=x) cnt++;
}

ll need=0;
for(int i=n-1;i>=0 && cnt<n-p;i--)
{
if(a[i].second && a[i].first<x)
{
need+=x-a[i].first;
if(need>k) return false;
cnt++;
}
}
//用n-p算比较方便
//如果 n=5 那么cnt应该大于或等于3 对应就是5-5/2
return cnt>=n-p;
};

auto findMid=[=](int pos)->ll
{
ll l=0,r=1e9;
while(l<r)
{
ll mid=(l+r+1)>>1;
if(check(mid,pos)) l=mid;
else r=mid-1;
}
return l;
};

ll maxMid_1=findMid(n/2);
ll maxMid_2=findMid(n/2-1);
for(int i=0;i<n;i++)
{
if(a[i].second==0)
{
//更上面的i<n/2原理一样 但是由于数组处理过,所以得这样写
if(a[i].first<maxMid_1) ans=max(ans,a[i].first+maxMid_1);
if(a[i].first>=maxMid_2) ans=max(ans,a[i].first+maxMid_2);
}
}
cout<<ans<<"\n";
}
int main()
{
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
 

D

可以从考虑Elsie什么时候能赢入手。

可以发现:如果Elise能赢,那么他一定是在某一次跳跃(也就是alternative bridges)后,跳到了Bessie的前面。这样他才有可能赢。

考虑详细一点:如果Elise能走到这一步,前提是什么?

  • Elise前面走过的岛屿,Bessie都没走过(每一轮Bessie先走),不然岛屿就会坍塌,Elise直接失败。所以Bessie肯定只能在Elise的jump起点之后的岛屿出发。
  • 在Elise到达jump的终点后,从起点出发的这段时间\(t\),Bessie肯定是不能到达jump的终点(记作\(y\))的,所以可以确定Bessie只能在\(y-t\)之前的岛屿开始出发。
  • 由上面,我们可以确定Bessie可以出发的一个区间。我们可以利用差分来标记这个区间,最后再统计答案。
  • \(t\)可以用\(dp\),我们只需要\(dp\)到达最后jump的起点的最短时间即可,这个很简单,新手都会的。

比较麻烦的一点是:因为数据是多组,所以如果开全局变量,每次clear会超时。所以只能开局部变量。

并且需要特判\(m=0\)的情况,不然会卡死。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int MAXN=2e5+10;
void solve()
{
int n,m; cin>>n>>m;
//思路 枚举jump+差分 维护答案
std::vector<pair<int,int>> vec(m,{0,0});
std::vector<int> dp(n+1,0);
if(m)
{
std::vector<std::vector<int>> edge(n+1);
for(int i=0;i<m;i++)
{
int u,v; cin>>u>>v;
vec[i].first=u,vec[i].second=v;
edge[v].push_back(u);
}

for(int i=1;i<=n;i++)
{
dp[i]=dp[i-1]+1;
for(auto t: edge[i])
{
dp[i]=min(dp[i],dp[t]+1);
}
}
}
else
{
for(int i=1;i<=n;i++)
{
dp[i]=i;
}
}
std::vector<ll> d(n+1,0);
for(auto &t: vec)
{
int x=t.first;
int y=t.second;
int need=dp[x]+1;
int end=y-need;
int begin=x+1;
if(begin<=end)
{
d[begin]+=1;
d[end+1]-=1;
}
}
int cnt=0;
for(int i=1;i<n;i++)
{
cnt+=d[i];
if(cnt>0) cout<<0;
else cout<<1;
}
cout<<"\n";
}
int main()
{
int t=1;
cin>>t;
while(t--) solve();
return 0;
}