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; });          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);         }         }          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++;              }         }                           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)         {                          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;          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; }  
   |