Codeforces-#642 A-E

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=1n1aiai+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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值