• Codeforces Round #642 (Div. 3)简要题解


    Codeforces Round #642 (Div. 3)

    传送门

    A. 给你n个数,和一个数字m。构建一个非负数组,使得其长度为n,数组的和为m。并且使得(sum_{i=0}^{n-1}abs(a[i+1]-a[i]))最大。

    ​ 可以想到,(n=1)的时候,答案是0。(n=2)的时候,答案是m。(n>=3)的时候,答案是2*m。0,m,0,...这种构造方案就可以了。

    #include<bits/stdc++.h>
    
    #define all(x) x.begin(),x.end()
    #define fi first
    #define sd second
    #define lson (nd<<1)
    #define rson (nd+nd+1)
    #define PB push_back
    #define mid (l+r>>1)
    #define MP make_pair
    #define SZ(x) (int)x.size()
    
    using namespace std;
    
    typedef long long LL;
    
    typedef vector<int> VI;
    
    typedef pair<int,int> PII;
    
    inline int read(){
        int res=0, f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
        return res*f;
    }
    
    const int MAXN = 200'005;
    
    const int MOD = 1000000007;
    
    void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
    int mulmod(int a, int b){return 1ll*a*b%MOD;}
    
    template<typename T>
    void chmin(T& a, T b){if(a>b)a=b;}
    
    template<typename T>
    void chmax(T& a, T b){if(b>a)a=b;}
    
    
    int main(){
        int t=read();
        while(t--){
            int n=read(),m=read();
            if(n==1){
                cout<<0<<endl;
            }else if(n==2){
                cout<<m<<endl;
            }else{
                cout<<2*m<<endl;
            }
        }
    
        return 0;
    }
    
    

    B. 两个长度为n的数组a,b。给你一个数字k。你最多进行k次操作,每一次形如swap(a[i],b[j])。问a数组和的最大值为多少?

    ​ a从小到大排序,b从大到小排序(或者都反过来)。考虑用b来提升a的和,这个时候肯定是拿b中最大的去换a中最小的,依次换就可以了,无法交换或者k次用尽就break出来。

    #include<bits/stdc++.h>
    
    #define all(x) x.begin(),x.end()
    #define fi first
    #define sd second
    #define lson (nd<<1)
    #define rson (nd+nd+1)
    #define PB push_back
    #define mid (l+r>>1)
    #define MP make_pair
    #define SZ(x) (int)x.size()
    
    using namespace std;
    
    typedef long long LL;
    
    typedef vector<int> VI;
    
    typedef pair<int,int> PII;
    
    inline int read(){
        int res=0, f=1;char ch=getchar();
        while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
        return res*f;
    }
    
    const int MAXN = 200'005;
    
    const int MOD = 1000000007;
    
    void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
    int mulmod(int a, int b){return 1ll*a*b%MOD;}
    
    template<typename T>
    void chmin(T& a, T b){if(a>b)a=b;}
    
    template<typename T>
    void chmax(T& a, T b){if(b>a)a=b;}
    
    void solve(){
        int n=read(),k=read();VI a(n),b(n);
        for(int i=0;i<n;++i)a[i]=read();
        for(int i=0;i<n;++i)b[i]=read();
    
        sort(all(a));reverse(all(a));
        sort(all(b));
    
        int cnt=0;
        for(int i=n-1;i>=0;--i){
            if(cnt==k)break;
            else{
                if(b[i]>a[i]){
                    ++cnt;
                    swap(b[i],a[i]);
                }else{
                    break;
                }
            }
        }
    
        cout<<accumulate(all(a),0)<<endl;
    }
    
    int main(){
        int t=read();
        while(t--){
            solve();
        }
    
        return 0;
    }
    
    

    C. 给一个n*n的网格,我们需要把所有的点收集到一个点上。每一个点可以走到相邻的八个格子,代价为1。问最小的代价。

    ​ 肯定是到最中心的那个格子最优,可以O(1)推式子,但没必要。随便写写就能过。

    #include<bits/stdc++.h>
    
    #define all(x) x.begin(),x.end()
    #define fi first
    #define sd second
    #define lson (nd<<1)
    #define rson (nd+nd+1)
    #define PB push_back
    #define mid (l+r>>1)
    #define MP make_pair
    #define SZ(x) (int)x.size()
    
    using namespace std;
    
    typedef long long LL;
    
    typedef vector<int> VI;
    
    typedef pair<int,int> PII;
    
    inline int read(){
        int res=0, f=1;char ch=getchar();
        while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
        return res*f;
    }
    
    const int MAXN = 200'005;
    
    const int MOD = 1000000007;
    
    void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
    int mulmod(int a, int b){return 1ll*a*b%MOD;}
    
    template<typename T>
    void chmin(T& a, T b){if(a>b)a=b;}
    
    template<typename T>
    void chmax(T& a, T b){if(b>a)a=b;}
    
    
    int main(){
        int t;cin>>t;
        while(t--){
            LL n;cin>>n;
            LL res=0;
            n/=2;
            for(int i=1;i<=n;++i){
                res+=1ll*i*8*i;
            }
            cout<<res<<endl;
        }
    
        return 0;
    }
    
    

    D. 长度为n的数组,里面初始元素都是0。考虑第i步,要将i这个数字放最长的且最靠左边的连续0的段的中间位置,输出最后的数组。

    ​ 用一个优先队列,长度为第一关键字,位置为第二关键字。每次放下之后,将剩下的连续0的段扔进队列。输出答案即可。

    #include<bits/stdc++.h>
    
    #define all(x) x.begin(),x.end()
    #define fi first
    #define sd second
    #define lson (nd<<1)
    #define rson (nd+nd+1)
    #define PB push_back
    #define mid (l+r>>1)
    #define MP make_pair
    #define SZ(x) (int)x.size()
    
    using namespace std;
    
    typedef long long LL;
    
    typedef vector<int> VI;
    
    typedef pair<int,int> PII;
    
    inline int read(){
        int res=0, f=1;char ch=getchar();
        while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
        return res*f;
    }
    
    const int MAXN = 200'005;
    
    const int MOD = 1000000007;
    
    void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
    int mulmod(int a, int b){return 1ll*a*b%MOD;}
    
    template<typename T>
    void chmin(T& a, T b){if(a>b)a=b;}
    
    template<typename T>
    void chmax(T& a, T b){if(b>a)a=b;}
    
    int ans[MAXN];
    
    int cnt;
    
    priority_queue<PII> q;
    
    void solve(){
        int n=read();
        cnt=0;
        q.push(MP(n,-1));
        while(!q.empty()){
            PII a=q.top();
            q.pop();
            int l=-a.sd,r=-a.sd+a.fi-1;
            ans[mid]=++cnt;
            if(mid>l)q.push(MP(a.fi/2-(a.fi%2==0),-l));
            if(r>mid)q.push(MP(a.fi/2,-mid-1));
        }
        for(int i=1;i<=n;++i)cout<<ans[i]<<" 
    "[i==n];
    }
    
    int main(){
        int t=read();
        while(t--){
            solve();
        }
    
        return 0;
    }
    
    

    E. 给一个长度为n的01字符串和一个整数k,每次操作可以将字符串中0变成1或者1变成0,代价是1。问最少多少次操作之后,可以将字符串中1的位置差全部变成k。

    ​ 首先,可以发现对k不同余的1的位置是没有办法同时保留的,所以,应该按照余k去分类。这个时候,如果将所有对k同余的位置中,1不变,0变成-1。我们只需要求一个最大字段和就可以得到位置个数最大值了(包括保留的1和减去了的填上的1),用这个值去更新答案即可。

    #include<bits/stdc++.h>
    
    #define all(x) x.begin(),x.end()
    #define fi first
    #define sd second
    #define lson (nd<<1)
    #define rson (nd+nd+1)
    #define PB push_back
    #define mid (l+r>>1)
    #define MP make_pair
    #define SZ(x) (int)x.size()
    
    using namespace std;
    
    typedef long long LL;
    
    typedef vector<int> VI;
    
    typedef pair<int,int> PII;
    
    inline int read(){
        int res=0, f=1;char ch=getchar();
        while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
        return res*f;
    }
    
    const int MAXN = 200'005;
    
    const int MOD = 1000000007;
    
    void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
    int mulmod(int a, int b){return 1ll*a*b%MOD;}
    
    template<typename T>
    void chmin(T& a, T b){if(a>b)a=b;}
    
    template<typename T>
    void chmax(T& a, T b){if(b>a)a=b;}
    
    char s[1000005];
    
    void solve(){
        int n=read(),k=read();
        scanf("%s",s+1);
    
        int tol=0;
        for(int i=1;i<=n;++i)if(s[i]=='1')++tol;
    
        int res=max(0,tol-1);
        for(int i=1;i<=k;++i){
            vector<int>nums;
            nums.PB(0);
            vector<int> dp(n/k+10,0);
            for(int j=i;j<=n;j+=k){
                if(s[j]=='1')nums.PB(1);
                else nums.PB(-1);
            }
    
            int mx=0;
            for(int j=1;j<SZ(nums);++j){
                dp[j]=max(dp[j-1]+nums[j],nums[j]);
                mx=max(mx,dp[j]);
            }
            res=min(res,tol-mx);
        }
    
        cout<<res<<endl;
    }
    
    int main(){
        int t=read();
        while(t--){
            solve();
        }
    
        return 0;
    }
    
    

    F. 给你一个(n*m)的网格((n<=100,m<=100)),里面每一个位置都有一个值。现在限定只能向右和向下走,且走的条件是下一个位置的值比当前位置值大1。现在每一次可以选取其中一个位置,将这个位置的值减少1。问最小操作多少次能够从((1,1))走到((n,n))

    ​ 首先,有一个重要的观察就是:我们考虑一条最优的路径,这路径上面一定是有一个位置的值是不变的。我们枚举这个值,可以得到((1,1))位置的高度(当然这里还有一个可不可行的问题,算一个细节)。这个时候,就变成了最简单的(dp)题目了,这个时候直接(dp)出到达(dp[n][m])的最小代价即可。

    #include<bits/stdc++.h>
    
    #define all(x) x.begin(),x.end()
    #define fi first
    #define sd second
    #define lson (nd<<1)
    #define rson (nd+nd+1)
    #define PB push_back
    #define mid (l+r>>1)
    #define MP make_pair
    #define SZ(x) (int)x.size()
    
    using namespace std;
    
    typedef long long LL;
    
    typedef vector<int> VI;
    
    typedef pair<int,int> PII;
    
    inline int read(){
        int res=0, f=1;char ch=getchar();
        while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
        return res*f;
    }
    
    const int MAXN = 200'005;
    
    const int MOD = 1000000007;
    
    void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
    int mulmod(int a, int b){return 1ll*a*b%MOD;}
    
    template<typename T>
    void chmin(T& a, T b){if(a>b)a=b;}
    
    template<typename T>
    void chmax(T& a, T b){if(b>a)a=b;}
    
    LL a[105][105];
    LL dp[105][105];
    
    int n, m;
    
    LL getDp(LL val){
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j){
                dp[i][j]=2e18;
            }
        }
    
        dp[0][0]=0;
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j){
                LL h=val+i+j+1;
                if(a[i+1][j]>=h)dp[i+1][j]=min(dp[i+1][j],dp[i][j]+a[i+1][j]-h);
                if(a[i][j+1]>=h)dp[i][j+1]=min(dp[i][j+1],dp[i][j]+a[i][j+1]-h);
            }
        }
    
        return dp[n-1][m-1];
    }
    
    void solve(){
        n=read(),m=read();
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j){
                scanf("%lld",a[i]+j);
            }
        }
    
      LL res=2e18;
      for(int i=0;i<n;++i){
        for(int j=0;j<m;++j){
            if(a[i][j]-i-j>a[0][0])continue;
            LL t=a[0][0]-(a[i][j]-i-j);
            t+=getDp(a[i][j]-i-j);
            res=min(res,t);
        }
      }
    
      cout<<res<<endl;
    }
    
    int main(){
        int t=read();
        while(t--){
            solve();
        }
    
        return 0;
    }
    
    
  • 相关阅读:
    Public Sale(巴什博弈)
    Harmonic Value Description (思维+找规律)
    放苹果+N的划分(青理工校赛J题) (动归)
    线段树求逆序数+北化校赛D题
    写给自己
    Euclid's Game (博弈论)
    Bear and Blocks (dp+思维)
    Maximum splitting(找规律+思维)
    Bone Collector II(DP+第K优解)
    Codeforces 950E Data Center Maintenance ( 思维 && 强连通分量缩点 )
  • 原文地址:https://www.cnblogs.com/JohnRan/p/12894755.html
Copyright © 2020-2023  润新知