A. Min Max Swap
题意:
有两个数组,我们可以将同一位置上的两个数相互交换,求两个数组各自的最大值的乘积的最小值
思路:
令第一个数组中每一个位置上的数都比第二个大,然后分别求两个数组的最大值再相乘即可得到结果。
代码:
#include<bits/stdc++.h>
using namespace std;
struct node
{
int a;
int b;
} c[1005];
bool comp(node x,node y)
{
return x.a<y.a;
}
int main()
{
int t;
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--)
{
int n,k;
cin>>n>>k;
memset(c,0,sizeof(c));
for(int i=1; i<=n; i++)
{
cin>>c[i].a;
}
for(int i=1; i<=n; i++)
{
cin>>c[i].b;
}
int sum=k;
sort(c+1,c+1+n,comp);
for(int i=1; i<=n; i++)
B. Fun with Even Subarrays
题意:
每次操作可以使得 al+i=al+k+i,问至少要多少次操作可以使得数组内的元素全部相等。
思路
从数组最后开始向前推即可
代码:
#include<bits/stdc++.h>
#include <bits/stdc++.h>
using namespace std;
int a[200005];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while (t--)
{
int n,ans=0;
cin>>n;
for (int i=1; i<=n; i++)
{
cin>>a[i];
}
int i=n-1;
while (i>0)
{
if (a[i]!=a[n])
{
ans++;
i=n-(n-i)*2;
}
else i--;
}
cout<<ans<<endl;
}
return 0;
}
C. And Matching
题意:
把0~n-1的所有数两两配对得到 n / 2 对数字,令每对数字的与运算的和等于k,求配对方式,如果不能配对,输出-1
思路
想办法让一组的结果为k,其余的所有结果都为0。
通过分析可知,对于任意的 i & ( n − 1 − k ) = 0,一定存在分组方式,让 n − 1和 k 配对,0 和 n − k 配对,其他数字使用上述结论处理。
这时 sum = ( ( n − 1 ) & k ) + ( 0 & ( n − k ) ) + 0 + . . . + 0 = k + 0 + 0 + . . . + 0 = k满足题意。
可以发现,当 k = n-1 时,上述操作不成立,当 k = n-1 时,让 n-1 与 n-2 配对,1 和 3 配对,0 和 n-4 配对,其他数字使用上述结论处理。
这时sum=((n−1)&(n−2))+(1&3)+(0&(n−4))+0+…+0=n−2+1+0+0+…+0=n−1=k,满足题意。
通过分析样例可以得知,当 n = 4 时,不存在这样的操作,所以输出 -1。
代码:
#include<bits/stdc++.h>
using namespace std;
const int mo=998244353;
int n,t,a[200005],b[200005],cnt,to[200005];
vector<int> pos[200005];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--)
{
cin>>n;
cnt=0;
for(int i=0; i<=n; i++)
{
pos[i].clear();
}
memset(to,0,sizeof(to));
for(int i=1; i<=n; i++)
{
cin>>a[i];
pos[a[i]].push_back(i);
}
int stp=0,st;
while(stp<n)
{
stp++;
for(int i=0;; i++)
{
while(to[i]<pos[i].size() && pos[i][to[i]]<stp)
{
to[i]++;
}
if(to[i]==pos[i].size())
{
b[++cnt]=i;
for(int j=0; j<i; j++)
stp=max(stp,pos[j][to[j]]);
break;
}
}
}
cout<<cnt<<endl;
for(int i=1; i<=cnt; i++)
{
cout<<b[i]<<' ';
}
cout<<endl;
}
}
D、Range and Partition
题意:
找到一个区间 [x,y],使得数组 a 可以划分为 k 个区间,且每个区间满足“区间内元素在[x,y] 的个数严格大于不在[x,y]的元素个数”,输出任意一组 x,y(要求y-x最小) 以及划分方法。
思路
定义数组a中在区间[x,y]的元素个数为 cnt。
如果满足cnt−(n−cnt)>=k,那么一定存在一种划分方法满足要求。
双指针枚举 1到 n 找到合法的并且 y − x最小的一组(x,y),先划分 k-1 满足的小区间(设区间长度为 len,cnt−(len−cnt)=1),留下的元素构造最后一个区间即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int a[1000005], v[1000005];
int main() {
int t;
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> t;
while(t--)
{
int n, k;
cin >> n >> k;
for(int i = 1; i <= n; i++)
v[i] = 0;
for(int i = 1; i <= n; i++)
{
cin >> a[i],;
v[a[i]]++;
}
int l = 1, r = 0, x = 1, y = n;
int cnt = 0;
while(r < n)
{
cnt += v[++r];
while(cnt - (n - cnt) >= k)
{
if(r-l < y-x)
{
x = l, y = r;
}
if(l+1 <= r)
{
cnt -= v[l++];
}
else
break;
}
}
cout << x << " " << y << endl;
int pos = 1; cnt = 0;
for(int i = 1; i <= n; i++)
{
if(cnt+1 == k)
{
cout << i << ' ' << n << endl;
break;
}
int cnt1 = 0, cnt2 = 0;
for(int j = i; j <= n; j++)
{
if(a[j] >= x && a[j] <= y) cnt1++;
else cnt2++;
if(cnt1 - cnt2 > 0)
{
pos = j+1;
break;
}
}
cout << i << " " << pos-1 << endl;
i = pos-1;
cnt++;
}
}
return 0;
}