A. Min Max Swap
题意:给出两个数组,每次可以交换下标相同的两个数。交换次数不限,求两个数组中最大值乘积的最小值。
解:一开始想的是排个序,求第n个和第2n个数的乘积。但可能有两个较大数相同,所以只能遍历一遍,把大的全换到a,求出相对最小值。
代码:

#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 1005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n; int a[maxx],b[maxx]; signed main() { int T; scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&b[i]); for(int i=1;i<=n;i++) if(a[i]<b[i]) swap(a[i],b[i]); sort(a+1,a+n+1); sort(b+1,b+n+1); printf("%d\n",a[n]*b[n]); } return 0; }
B. Fun with Even Subarrays
题意:给出一个数组。每次可以选择一个长度为偶数的区间,使左边一半等于右边一半。求使得整个数组相同的最小次数。
解:开始看反了。。。由于是左边等于右边,所以从右边开始遍历,碰到不相同的pia过去。
代码:

#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 200005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n; int a[maxx]; signed main() { int T; scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); int cnt=1,ans=0; int i=n-1; while(i>0){ if(a[i]==a[n]) { cnt++; i--; } else{ cnt*=2; i=n-cnt; ans++; } } printf("%d\n",ans); } return 0; }
C. And Matching
题意:给出n和k,要求将0到n-1的数两两配对,其与运算之和为k。保证n为2的幂。
解:怎么简单怎么来。显然 i 与 n-i-1 与之和为0。现在留出k,那么要给n-k-1找对象(?,使得它们与出来是0。0显然满足这个要求。现在留下n-1和k,n-1和k与完还是k,完美。考虑到k=n-1时不能这么干,那多拉两个和它们配对,最终在只要对称即可。n-1和n-2可以整出k-1,现在留下0和1要整出1,不够,那拉上n-3和2。n-3的末尾显然是1,问题解决。这样需要6个数,也就是n=4,k=3时无解,特判即可。
代码:

#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 45 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n,k; int vis[70005]; signed main() { int T; scanf("%d",&T); while(T--){ for(int i=0;i<n;i++) vis[i]=0; scanf("%d%d",&n,&k); if(n==4){ if(k==0) printf("0 3\n1 2\n"); else if(k==1) printf("1 3\n0 2\n"); else if(k==2) printf("0 1\n2 3\n"); else if(k==3) printf("-1\n"); continue; } if(k==0){ for(int i=0;i<n/2;i++) printf("%d %d\n",i,n-1-i); continue; } if(k==n-1){ printf("%d %d\n",n-1,n-2); printf("%d %d\n",1,n-3); printf("2 0\n"); for(int i=3;i<n/2;i++) printf("%d %d\n",i,n-i-1); continue; } printf("%d %d\n",k,n-1); printf("%d %d\n",n-k-1,0); for(int i=1;i<n/2;i++){ if(i==k||n-i-1==k) continue; printf("%d %d\n",i,n-i-1); } } return 0; }
D. Range and Partition
题意:要求将n个数分为k组,每组中在范围[x,y]内的数严格大于不在其中的数。现给出n个数,求x和y以及对应的分割方案,并要求y-x之差最小。
解:第一遍读题的时候读成了组内在范围的数大于组外不在范围内的数,想这怎么搞。看了样例恍然大悟。考虑到得到x和y后很好分组,决定二分,先考虑二分y-x,但很难搞。于是考虑枚举x和y,套路地枚举左端点,二分右端点,O(n)验证。但这样复杂度变成了O(n2logn),会T。优化验证,通常到了这时候可不可行能直接算出来。有k个区间,每个区间贪心地让范围内的比范围外的至少多一个,一共多k个。这k个不管怎么分布凑合凑合好像都能分出来。问题解决。
代码:

#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n,k; int a[maxx]; int num[maxx]={0}; signed main() { int T; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=0;i<=n;i++) num[i]=0; for(int i=1;i<=n;i++) num[a[i]]++; for(int i=1;i<=n;i++) num[i]+=num[i-1]; int x=1,y=n; for(int i=1;i<=n;i++){ int l=i,r=n,mid,ans=inf; while(l<=r){ mid=(l+r)/2; int in=num[mid]-num[i-1],out=n-in; if(in-out>=k) ans=mid,r=mid-1; else l=mid+1; } if(ans!=inf&&ans-i<y-x) x=i,y=ans; } printf("%d %d\n",x,y); int cnt=0,cnt1=0,cnt2=0,s=1; for(int i=1;i<=n;i++){ if(x<=a[i]&&a[i]<=y) cnt1++; else cnt2++; if(cnt1>cnt2){ if(cnt==k-1){ printf("%d %d\n",s,n); break; } printf("%d %d\n",s,i); s=i+1; cnt++; cnt1=cnt2=0; } } } return 0; }
*E. Paint the Middle
题意:给出1-n的一组数,每次选出相同且未上色的两个数,然后可以给它们之间任何一个数上色。求最多上色个数。
解:研究了一下是个区间问题。有若干个端点不同的区间,边沿上色了里面就不能上色。区间不重叠时很好解,那么现在考虑重叠的情况。有2个重叠时,要删3个点;3个重叠时,要删4个点。总结一下,每个区间的头删掉,加上最后一个的尾巴,完美,开始写代码。先整理出线段,统计有几个重叠,更新答案,提交!然后,
QAQ
最后绷不住了去看tutorial,发现思路是一样的,研究了半天发现统计有几个重叠线段时会加入不必要的条数,比如:
红色标注的那条是不必要的,但如果按左端点排序统计线段条数,更新右边界,会把它算进去。
那么现在问题就是在当前区间中找到右端点最大的,我屈服了,看了status里的写法。大意就是每次更新右边界,判断当前点是否在第一个区间内,如果是ans++,超出区间进入直接跑到右端点,orz
代码:

#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n,k; int a[maxx]; int s[maxx]={0},e[maxx]={0}; vector<pair<int,int> > seg; signed main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) e[a[i]]=i; int ans=0,l=0,r=0; for(int i=1;i<=n;i++){ r=max(r,e[a[i]]); if(l>i) ans++; else l=r; } printf("%d\n",ans); return 0; }
F. Flipping Range
题意:给出数组a和b,每次可以从b里挑选一个数x,将a中任意一个长为x的子数组正负号反转。操作次数不限,求a数组所有数之和最大值。
解:首先将b的操作化为一种操作,即每次改变gcd(b[1]...b[m])长度的子数组,然后考虑怎样使和最大。最理想的情况是所有负的变成整的。考虑如何达到这种情况。设gcd值为g,则每次改变g个数。将a按照模g的值分为g组,每进行一次操作,每组都有刚好一个数改变,如果最后每组改变的数量相同,那么这种情况是可达的。这样共有2g种情况,还是很大,考虑压缩,用它们的异或值0或1代表其状态。其实挺难想的,证明也是找到结论再证,那记一下吧。然后就可以用dp[i][0/1]表示余数为i,异或和为0/1时最大值。
代码:

#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 1000005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n,m; ll a[maxx],b[maxx]; ll dp[maxx][2]; ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); } signed main() { int T; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); for(int i=1;i<=m;i++) scanf("%lld",&b[i]); ll g=0; for(int i=1;i<=m;i++) g=gcd(g,b[i]); for(int i=0;i<=g-1;i++) dp[i][0]=0,dp[i][1]=-inf; for(int i=1;i<=n;i++){ int t=i%g; ll t0=max(dp[t][0]+a[i],dp[t][1]-a[i]); ll t1=max(dp[t][0]-a[i],dp[t][1]+a[i]); dp[t][0]=t0;dp[t][1]=t1; } ll sum0=0,sum1=0; for(int i=0;i<=g-1;i++){ sum0+=dp[i][0]; sum1+=dp[i][1]; } printf("%lld\n",max(sum0,sum1)); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?