The 2021 ICPC Asia Nanjing Regional Contest (XXII Open Cup, Grand Prix of Nanjing)
A.Oops, It’s Yesterday Twice More
思路:考虑先把所有袋鼠集中在一起然后再移动。因为有步数限制(
// AC one more times // nndbk #include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int N = 2e5 + 10; int n,a,b; int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); cin>>n>>a>>b; //LU int x = 1,y = 1; if((a-x)+(b-y)<=(n-1)) { for(int i = 1;i <= n-1;i++)cout<<"L"; for(int i = 1;i <= n-1;i++)cout<<"U"; for(int i = 1;i <= b-y;i++)cout<<"R"; for(int i = 1;i <= a-x;i++)cout<<"D"; return 0; } //RU x = 1,y = n; if((a-x)+(y-b)<=(n-1)) { for(int i = 1;i <= n-1;i++)cout<<"R"; for(int i = 1;i <= n-1;i++)cout<<"U"; for(int i = 1;i <= y-b;i++)cout<<"L"; for(int i = 1;i <= a-x;i++)cout<<"D"; return 0; } //LD x = n,y = 1; if((x-a)+(b-y)<=(n-1)) { for(int i = 1;i <= n-1;i++)cout<<"L"; for(int i = 1;i <= n-1;i++)cout<<"D"; for(int i = 1;i <= b-y;i++)cout<<"R"; for(int i = 1;i <= x-a;i++)cout<<"U"; return 0; } //RD x = n,y = n; if((x-a)+(y-b)<=(n-1)) { for(int i = 1;i <= n-1;i++)cout<<"R"; for(int i = 1;i <= n-1;i++)cout<<"D"; for(int i = 1;i <= y-b;i++)cout<<"L"; for(int i = 1;i <= x-a;i++)cout<<"U"; return 0; } return 0; }
C. Klee in Solitary Confinement
思路:
做法一:(公式推导)我们考虑枚举众数是谁,然后去写。对于众数是

如上图所示:
为了更快的处理区间问题,我们先预处理出对于某个数
那么对于
移向得:
因为
还有一个问题,如何处理出这个东西?
我们先用
对于时间复杂度:因为每个数
注意:下标有负数,我们做个偏移。
// AC one more times // nndbk #include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int N = 4e6 + 10,M = 2e6; vector<int>idx[N]; int pos[N]; int cnt[N]; int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); int n,k; cin>>n>>k; ll maxn = -1e9; ll res = -1e18; for(int i = 1;i <= n; i++) { ll x; cin>>x; x += M; cnt[x]++; if(cnt[x]>res)res = cnt[x]; maxn = max(maxn,x); idx[x].push_back(i); } //cout<<"mx = "<<maxn<<"\n"; for(int i = 0;i <= 4e6; i++) { int c = 0; int x = i,y = i+k; if(y<0||y>4e6)continue; int sz1 = idx[x].size(),sz2 = idx[y].size(); if(y<0||y>4e6||sz1==0||sz2==0)continue; //cout<<"x = "<<x-M<<" y = "<<y-M<<"\n"; int cnt1 = 0,cnt2 = 0; while(cnt1 < sz1|| cnt2 < sz2) { if(cnt1 == sz1) pos[idx[y][cnt2]] = ++c,cnt2++; else if(cnt2 == sz2) pos[idx[x][cnt1]] = ++c,cnt1++; else{ if(idx[x][cnt1] < idx[y][cnt2]) pos[idx[x][cnt1]] = ++c,cnt1++; else pos[idx[y][cnt2]] = ++c,cnt2++; } } // cout<<"pos1 :"; // for(int i = 0;i<sz1;i++) // cout<<pos[idx[x][i]]<<" "; // cout<<"\n"; // cout<<"pos2 :"; // for(int i = 0;i<sz2;i++) // cout<<pos[idx[y][i]]<<" "; // cout<<"\n"; vector<ll>pre1(c+1),pre2(c+1); for(auto j:idx[x]) pre1[pos[j]]++; for(auto j:idx[y]) pre2[pos[j]]++; for(int i = 1; i <= c; i++) pre1[i] += pre1[i-1],pre2[i] += pre2[i-1]; // for(int i = 1;i <= c;i++) // cout<<pre1[i]<<" "; // cout<<"\n"; // for(int i = 1;i <= c;i++) // cout<<pre2[i]<<" "; // cout<<"\n"; ll t = 0; for(int i = 1;i <= c; i++) { t += (pre1[i]-pre1[i-1])-(pre2[i]-pre2[i-1]); if(t<0)t = 0; res = max(res,t + pre2[c]); } } cout<<res<<"\n"; return 0; }
做法二:
考虑一个区间
对于一个区间原本的数是
如果选择
那么如何选区间呢?从开始一直去取,直到某个位置贡献小于0了,那就不要这段了,因为从这段负的继续加不会更优。所以我们把这段区间丢掉,从新开始计算贡献。
// AC one more times // nndbk #include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int N = 4e6 + 10,M = 2e6; vector<int>idx[N]; int ret[N],a[N],pre[N],cnt[N]; int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); int n,k; cin>>n>>k; int ans = 0; for(int i = 1;i <= n; i++) { cin>>a[i]; cnt[a[i]+M]++; ans = max(ans,cnt[a[i]+M]); } if(k==0){ cout<<ans<<"\n"; return 0; } for(int i = 1;i <= n; i++) { ret[a[i]+M]--; if(ret[a[i]+M]<0)ret[a[i]+M] = 0; ret[a[i]+k+M]++; ans = max(ans,cnt[a[i]+k+M]+ret[a[i]+k+M]); } cout<<ans<<"\n"; return 0; }
思想:边扫边统计答案,无需先确定区间再去算。
J. Xingqiu's Joke
思路:对于同时
若
而
// AC one more times // nndbk #include <bits/stdc++.h> using namespace std; typedef long long ll; #define ll int const int mod = 1e9 + 7; const int N = 2e5 + 10; vector<ll>d; void div(ll x) { for (ll i = 2; i <= x / i; i++) { if (x % i == 0) { int s = 0; while (x % i == 0) { x = x / i; s++; } d.push_back(i); } } if (x > 1)d.push_back(x); } map<pair<ll,ll>,ll>dp; ll dfs(ll a,ll c) { if(a==1)return 0; if(c==1)return a-1; ll &res = dp[{a,c}]; if(res)return res; res = a-1; for(auto g : d) { if(c % g == 0) { int left = a%g; ll t1 = left+1+dfs(a/g,c/g); ll t2 = (g-left)+1+dfs(a/g+1,c/g); res = min({res,t1,t2}); } } return res; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); int t; cin>>t; while(t--) { ll a,b; cin>>a>>b; d.clear(); dp.clear(); if(a>b)swap(a,b); ll c = abs(a-b); div(c); // for(auto g : d) // cout<<g<<" "; // cout<<"\n"; cout<<dfs(a,c)<<"\n"; } return 0; }
M. Windblume Festival
思路:分类讨论。
- 有正有负。用负数一直减正数。最后用正数减负数这样最优。结果是
- 全正。先变出一个负数之后,变成第一种情况。
- 全负。先变出一个正数之后,变成第一种情况。
因为
注意:特判
// AC one more times // nndbk #include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int N = 1e6 + 10; ll a[N]; int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); int t; cin>>t; while(t--) { int n; cin>>n; int cntn = 0,cntp = 0; ll sum = 0; for(int i = 0;i < n; i++) { cin>>a[i]; sum += abs(a[i]); if(a[i]<0)cntn++; else if(a[i]>0)cntp++; } if(n==1) { cout<<a[0]<<"\n"; continue; } ll ans = -1e18; if(cntn>0&&cntp>0) { ans = sum; } else if(cntn) { for(int i = 0;i < n; i++) { if(a[i]-a[(i+1)%n]>=0) ans = max(ans,(a[i]-a[(i+1)%n])+sum+a[i]+a[(i+1)%n]); } } else if(cntp) { for(int i = 0;i < n; i++) { if(a[i]-a[(i+1)%n]<=0) ans = max(ans,sum-(a[i]-a[(i+1)%n])-a[i]-a[(i+1)%n]); } } else ans = 0; cout<<ans<<"\n"; } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了