其他分享
首页 > 其他分享> > Codeforces Round #627 (Div. 3)【ABCDEF】(题解)

Codeforces Round #627 (Div. 3)【ABCDEF】(题解)

作者:互联网

目录


涵盖知识点:思维、dp、树形dp。

比赛链接:传送门

A - Yet Another Tetris Problem

题意: 俄罗斯方块
题解: 判断所有数的奇偶性
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=110;
int a[maxn];
int main(){
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        bool flag=true;
        int base=a[1]&1;
        for(int i=2;i<=n;i++){
            if((a[i]&1)!=base){
                flag=false;
                break;
            }
        }
        puts(flag?"YES":"NO");
    }
    return 0;
}

B - Yet Another Palindrome Problem

题意: 问能否找一个子序列,其为长度为3的回文串
题解: 两个相同数中间还有任意的数字即可。
Accept Code:写的有点丑。。。讲道理\(n^2\)扫一遍就完事了

#include <bits/stdc++.h>
using namespace std;
const int maxn=5050;
int a[maxn];
vector<int> v[maxn];
int main(){
    int t;
    cin>>t;
    while(t--){
        for(auto & i : v){
            i.clear();
        }
        int n;
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            v[a[i]].push_back(i);
        }
        bool flag=false;
        for(int i=1;i<maxn;i++){
            if(v[i].size()==0||v[i].size()==1)continue;
            if(v[i].size()>2){
                flag=true;
                break;
            }
            for(int j=1;j<v[i].size();j++){
                if(v[i][j]-v[i][j-1]>1){
                    flag=true;
                    goto st;
                }
            }
        }
        st:
        puts(flag?"YES":"NO");
    }
    return 0;
}

C - Frog Jumps

题意: 一个蛤在第\(i\)块只能根据该块的指定方向跳\([1,d]的距离\)求最小的\(d\)使得蛤能从\(0\)跳到\(n+1\)。
题解: 找最长的连续L串。长度再加1就行了。证明自行脑补。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=5050;
int a[maxn];
int main(){
    int t;
    cin>>t;
    while(t--){
        string s;
        cin>>s;
        s='R'+s;
        int cnt=0,ans=0;
        for(char i:s){
            if(i=='L'){
                cnt++;
            }
            else{
                ans=max(ans,cnt);
                cnt=0;
            }
        }
        ans=max(ans,cnt);
        cout<<ans+1<<"\n";
    }
    return 0;
}

D - Pair of Topics

题意: 问有多少对\((i,j)\)使得\(a_i+a_j>b_i+b_j\)
题解: 移项得到\(a_i-b_i>b_j-a_j\)。我们令\(c_i=a_i-b_i\),然后将其从大到小排序。双指针\(i,j\)分别从左右扫描。当\(c_i>-c_j\)时,对答案有\(j-i\)的贡献。当\(i\ge j\)时结束扫描即可。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int a[maxn],b[maxn],c[maxn];
typedef long long ll;
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1;i<=n;i++) {
        cin >> b[i];
        c[i]=a[i]-b[i];
    }
    sort(c+1,c+1+n,greater<int>());
    int pos=n;
    ll ans=0;
    for(int i=1;i<=n;i++){
        while (c[i]+c[pos]<=0&&pos>i)pos--;
        if(i>=pos)break;
        ans+=1ll*pos-i;
    }
    cout<<ans<<"\n";
    return 0;
}

E - Sleeping Schedule

题意: 现在一天\(h\)小时,总共要睡\(n\)次,一次睡一天,第\(i\)次 醒来之后可以选择\(a_i\)或者\(a_i-1\)个小时以后接着睡。如果醒来的时候在区间\([l,r]\)内,我们认为睡眠是好的。问最多能睡几次好的。
题解: \(dp_{i,j}\)描述睡了\(i\)次醒来的时候是\(j\)的最优情况。初值:\(dp_{0,0}=0,x=(j+a[i]-1)mod\ h,y=(j+a[i])mod\ h\)
转移方程:
\[\begin{cases} dp_{i,x}=max(dp_{i-1,j}+[l\le x \le r])\\ dp_{i,y}=max(dp_{i-1,j}+[l\le y \le r]) \end{cases} \]
所求值:\(max(dp[n])\)
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=2010,inf=0x3f3f3f3f;
int dp[maxn][maxn],a[maxn];
int n,h,l,r;
bool check(int x){
    return x>=l&&x<=r;
}
int main(){
    cin>>n>>h>>l>>r;
    for (int i = 1; i <= n; i++) {
        cin>>a[i];
    }
    memset(dp,-inf,sizeof dp);
    dp[0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<h;j++){
            int x=(j+a[i]-1)%h;
            dp[i][x]=max(dp[i][x],dp[i-1][j]+check(x));
            x++;
            x%=h;
            dp[i][x]=max(dp[i][x],dp[i-1][j]+check(x));
        }
    }
    int ans=0;
    for(int i=0;i<h;i++)
        ans=max(ans,dp[n][i]);
    cout<<ans<<"\n";
    return 0;
}

F - Maximum White Subtree

题意: 一棵无根树,有黑白两种点,问每个点的所有子树中白点数-黑点数的最大值。
题解: 记黑点为-1,白点为1.默认以1号点为根\(dfs\)扫一遍,从叶子节点向根做一遍树形dp。
转移方程:\(dp_u=\displaystyle\sum_{v\in son_u}max(dp_v,0)\)
再次\(dfs\)扫描一遍,在向下扫描的过程中,我们先假设断开\(u,v\)之间的连接,那么\(ans_u=max(ans_u-max(dp_v,0),0)\),那么\(ans_v=dp_v+ans_u\)。好像有点绕。。画个图脑补一下就好了。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int a[maxn],ans[maxn],dp[maxn];
vector<int> edg[maxn];
void dfs1(int root,int fa){
    dp[root]=a[root];
    for(auto v:edg[root]){
        if(v==fa)continue;
        dfs1(v,root);
        dp[root]+=max(dp[v],0);
    }
}
void dfs2(int root,int fa,int res){
    ans[root]=dp[root]+res;
    for(auto v:edg[root]){
        if(v==fa)continue;
        dfs2(v,root,max(ans[root]-max(dp[v],0),0));
    }
}
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(!a[i])a[i]=-1;
    }
    for(int i=1;i<=n-1;i++){
        int u,v;
        cin>>u>>v;
        edg[u].push_back(v);
        edg[v].push_back(u);
    }
    dfs1(1,0);
    dfs2(1,0,0);
    for(int i=1;i<=n;i++){
        cout<<ans[i]<<" ";
    }
    return 0;
}

标签:max,627,int,题解,Codeforces,maxn,ans,root,dp
来源: https://www.cnblogs.com/charles1999/p/12485781.html