codeforces #642 Div3
A. Most Unstable Array
题意:给你一个n和m,n是数组的大小,m是数组所有元素的和,然后让你自定义数组使得 ∑ i = 1 n − 1 ∣ a i − a i + 1 ∣ \displaystyle\sum_{i=1}^{n-1} |ai−ai+1| i=1∑n−1∣ai−ai+1∣最大,且数组元素大于等于0。
思路:很明显贪心做法就是隔一个数之间就安排0,然后其他的数就将m平分下去就可。例如n=10,m=20,就要插入5个0,还剩五个位置平分20就是4,最后就是 0 4 0 4 0 4 0 4 0 4,结果就是36。
特殊情况就是n为 1和2 的时候
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
typedef long long ll;
const int maxn=2e5+10;
int a[maxn];
int main(){
int t;
cin >> t;
while(t--){
ll n,m;
cin >> n >> m;
if(n==1){
cout << "0" << endl;
continue;
}
if(n==2){
cout << m << endl;
continue;
}
ll nn=n/2;
ll temp1=m/nn,temp2=m%nn;
ll ans=temp1*nn*2+temp2*2;
cout << ans << endl;
}
return 0;
}
B. Two Arrays And Swaps
题意:给你n和k,和两个大小为n的数组a和b,你每次操作可以交换两个数组元素,操作次数不大于k,然后问你操作后的a数组最大元素和是多少。
思路:贪心,将数组排序后,然后从b数组最大的元素和a数组最小的元素开始,如果b数组大于a数组就交换,然后更新两个指针位置继续判断,否则就结素操作。
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
typedef long long ll;
const int maxn=2e5+10;
int a[maxn],b[maxn];
int main(){
int t;
cin >> t;
while(t--){
int n,k;
cin >> n >> k;
for(int i=0;i<n;i++) cin >> a[i];
for(int i=0;i<n;i++) cin >> b[i];
sort(a,a+n);
sort(b,b+n);
int l=0,r=n-1;
while(k&&l<n&&r>=0){
if(a[l]<b[r]){
swap(a[l],b[r]);
k--;
l++;
r--;
}
else break;
}
int sum=0;
for(int i=0;i<n;i++) sum+=a[i];
cout << sum <<endl;
}
return 0;
}
C. Board Moves
题意:给你一个n x n的矩阵,保证n为奇数,矩阵每个位置上都有一个物体,它每次可以移动到相邻的八个位置上,每个位置可以容纳多个物体,问将所有物体移到同一位置需要多少次操作。
思路:贪心,很明显就是将所有物体移到最中心的物体上。
然后就成了一圈一圈的正方形,每一圈移动到最中心的次数是一样的,预处理一下1-5e5,然后O(1)查询即可。
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
typedef long long ll;
const int maxn=5e5+10;
ll a[maxn];
void sol(){
a[0]=0;
ll cnt=0;
for(ll i=1;i<=maxn;i++){
ll temp=i*2+1;
a[i]=a[i-1]+(temp*2+(temp-2)*2)*i;
}
}
int main(){
int t;
sol();
cin >> t;
while(t--){
ll n;
cin >> n;
cout << a[n/2] << endl;
}
return 0;
}
D. Constructing the Array
题意: 给你一个大小为n且全为0的数组a,你要将1-n插入到数组中去,插入顺序就是选取最长连续0串,如有相同大小的0串则选最左边的串,选取之后将a[(L+R)/2 ]的位置置为操作次数,例如n为10,则开始L=1,R=10,则a[5]=1,第二次L=6,R=10,a[8]=2…
思路:按题意模拟递归下去即可,将剩余串丢入一个优先队列中去,然后每次取出串来操作,再加入新生成的串即可,和归并排序挺像的,直接一直归下去就行。优先队列要自己写规则。
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define mk make_pair
typedef long long ll;
const int maxn=5e5+10;
ll a[maxn];
int cnt=1;
struct Node{
int l,r;
friend bool operator<(Node a,Node b){
if((a.r-a.l)!=(b.r-b.l)) return (a.r-a.l)<(b.r-b.l);
else return a.l>b.l;
}
};
priority_queue<Node>q,q2;
int main(){
int t;
// sol();
cin >> t;
while(t--){
while (!q.empty()) q.pop();
ll n;
cin >> n;
cnt=1;
q.push(Node{1,n});
int cnt=1;
while(!q.empty()){
Node t1=q.top();
q.pop();
int l=t1.l,r=t1.r;
if((r-l+1)%2){
int mid=(l+r)/2;
a[mid]=cnt++;
if(l<mid) q.push(Node{l,mid-1}));
if(r>mid) q.push(Node{mid+1,r}));
}
else{
int mid=(l+r)/2;
a[mid]=cnt++;
q.push(Node{mid+1,r});
if(l<mid) q.push(Node{l,mid-1});
}
}
for(int i=1;i<=n;i++) cout << a[i] << " ";
cout << endl;
}
return 0;
}
E. K-periodic Garland
题意:给你一个n和k,再给一个长度为n的01串,你每次操作可以将0置为1或1置为0,要保证操作之后的串中相邻的1间隔为k,求最小操作次数。
思路:dp,dp[i]表示以 i 位置为最后一个1的最小操作次数。每个dp操作要考虑当前i为该串的第一个1,或不为第一个1的情况,两者取最小。为第一个1时就是要将之前的所有1都置为0,dp[i]就是之前1的个数,不为第一个1时就是 dp[i] = min(dp[i], dp[i - k] + check(i - k + 1, i - 1) + (s[i - 1] == ‘0’));
check(L,R)函数返回的是L到R之间1的个数。
这个题解是我参考的一个b站up的,下面是链接
链接: link.
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define mk make_pair
typedef long long ll;
const int maxn=1e6+10;
ll a[maxn];
int cnt=1;
int dp[maxn], sum[maxn];
int check (int l, int r){
return sum[r] - sum[l - 1];
}
void sol(){
int n, k; cin >> n >> k;
string s; cin >> s;
for (int i = 0; i < n; i++) {
sum[i + 1] = sum[i] + (s[i] == '1');
}
if (sum[n] == 0) {
cout << 0 << '\n';
return;
}
int ans = maxn;
for (int i = 0; i < n; i++) {
int res = sum[i] + sum[n] - sum[i + 1];
res += (s[i] == '0');
ans = min(ans, res);
}
dp[0] = 0;
for (int i = 1; i <= n; i++) {
dp[i] = sum[i - 1] + (s[i - 1] == '0');
if (i >= k) {
dp[i] = min(dp[i], dp[i - k] + check(i - k + 1, i - 1) + (s[i - 1] == '0'));
}
}
for (int i = 1; i <= n; i++) {
ans = min(ans, dp[i] + sum[n] - sum[i]);
}
cout << ans << '\n';
}
int main(){
int t;
cin >> t;
while(t--){
// cout << "fkej" << endl;
sol();
//cout << "fopj" << endl;
}
return 0;
}