Codeforces每日一练 533E+235A+533B

533E Correcting Mistakes

传送门
镜像传送门
字符串+思维
给你两个不同的字符串,向每个字符串里加一个字母使得两个字符串一致,问可能的加入方法有多少种。
(为啥tag里会有dp~~~)
先把两端一样的部分删去,留下中间的的部分(想起了昨晚的D题QAQ),根据之前删除的方法,可以确定两个字符串中间部分两端的字母一定不相同,那么我们在加字母的时候只能在两端加,因为加在中间并不影响两端是否匹配,那么答案最多有两种,我们可以选择第一个加在前面第二个加在后面或者相反的方法,对于第一种方法,如果第一个字符串1—len-1和第二个字符串2—len是相同的,那么该方法就成立,同理我们可以判断第二种方法,都成立输出2,成立一个输出1,否则输出0.

signed main()
{
    ios ; cin.tie(0) , cout.tie(0);
    int n;
    cin>>n;
    string s,t;
    cin>>s;
    cin>>t;
    set<int> pos;
    int l=-1,r=-1;
    for (int i = 0; i <n ; ++i) {
        if(s[i]!=t[i]){
            pos.insert(i);
        }
    }
    if(pos.size()==1){cout<<2;return 0;}
    l=*pos.begin();
    auto m=pos.end();
    m--;
    r=*m;
    string s1,s2,t1,t2;
    for (int j = l+1; j <=r ; ++j) {
        s1+=s[j];
        s2+=s[j-1];
        t1+=t[j-1];
        t2+=t[j];
    }
    if(s1==t1||s2==t2){
        if(s1==t1&&s2==t2)cout<<2;
        else cout<<1;
    }
    else cout<<0;
    return 0;
}

235A LCM Challenge

传送门
镜像传送门
数论
在小于等于n的数里找三个数(可以相同)使他们的最小公倍数最大。
1/2肯定要特判,对于>2的,当n为奇数时,显然答案是n*(n-1)(n-2),三者必定互质,因为不互质奇数的gcd最大为3,那么两者的差肯定大于等于3,而n和n-2相差2,偶数和奇数不互质,差同样大于等于3。三者的积即为当前答案。如果n为偶数,只需要在几个选择里挑选即可,第一种为n×(n-1)×(n-2)/2,如果选n-2之后的偶数肯定是没有n-2优的,第二种为(n-1)×(n-2)×(n-3),即再构造一个相邻的奇偶奇,第三种为n×(n-1)×(n-3)/gcd(n,n-3),即继续向后找一个奇数,对于后面的奇数,肯定没有当前优,因为后面的奇数n小于n^2-5n<第二种里的(n-2)×(n-3)。
代码

signed main()
{
    ios ; cin.tie(0) , cout.tie(0);
    ll n;
    cin>>n;
    ll a=n,b=n-1,c=n-2;
    if(n==1)cout<<1;
    else if(n==2)cout<<2;
    else {
        if(n%2)cout<<a*b*c;
        else{
            ll ans=max(n*(n-1)*(n-2)/2,(n-2)*(n-1)*(n-3));
            ans=max(ans,n*(n-1)*(n-3)/gcd(n,n-3));
            cout<<ans;
        }
    }
    return 0;
}

533B Work Group

传送门
镜像传送门
公司里总裁编号是1,其他人编号2-n,每个人有自己的直接上司和自己的工作效率值,现在选择一部分人,使得小组里每个人都有偶数个下属,并且使这些人的工作效率和最大。
很明显是一道树形dp,问题在于怎么样转移方程。对于以每个节点为根的子树,有两种情况,取奇数个下属或者取偶数个下属(分别以1/0表示),可以考虑开个二维数组分别存奇数和偶数的情况,对于每个结点x,依次考虑以他的直接下属为根的子树,显然dp[x][0]=max(dp[x][1]+dp[i][1],dp[x][0]+dp[i][0]),dp[x][1]同理,因为我们是依次加入子树,所以并不会互相影响,但要注意每个结点的dp[x][1]要初始化为极小值,防止第一次转移时dp[x][0]=dp[i][1]。考虑完所有直接下属,回到当前节点,dp[x][1]有两种情况,不取当前结点取奇数个,取当前结点然后取偶数个,二者取最大值即可。
对于最后的答案,显然是dp[1][0]+a[1]和dp[1][1]的最大值,不取1,其余节点必取奇数个(否则没有取1优),或者取1,其余节点取偶数个,而在dfs里我们已经处理过二者的最大值,直接输出dp[1][1]即可。

int n;
#define maxn 200005
vector<int> g[maxn];
int a[maxn],dp[maxn][2];
void calc(int x,int fa){
    dp[x][0]=0;
    dp[x][1]=-100000000;
    for(auto i:g[x]){
        if(i!=fa){
            calc(i,x);
            int l=dp[x][0],r=dp[x][1];
            dp[x][0]=max(l+dp[i][0],r+dp[i][1]);
            dp[x][1]=max(r+dp[i][0],dp[i][1]+l);
        }
    }
    if(g[x].empty()){
        dp[x][0]=0;
        dp[x][1]=a[x];
    }
    dp[x][1]=max(dp[x][0]+a[x],dp[x][1]);
}
signed main()
{
    ios ; cin.tie(0) , cout.tie(0);
    cin>>n;
    rep(i,1,n){
        int p;
        cin>>p>>a[i];
        if(p!=-1)g[p].push_back(i);
    }
    calc(1,-1);
    cout<<dp[1][1];
    return 0;
}

(ps:数论题讲起来真麻烦QAQ

posted @ 2020-03-20 19:06  Bazoka13  阅读(87)  评论(0编辑  收藏  举报