Codeforces Round #722 (Div. 2)

2021.5.24

B

题意:给一个长度为n的序列,计算该序列的最长“奇怪”子序列长度为多少?其中奇怪序列的定义为序列里的任何一对数的差值大于等于序列的最大值。

题解:计算一下序列里负数个数ans0,0的个数ans1,正数的个数ans2,当ans1>=2,那么答案为ans0+ans1,否则可以判断是否拿正数,易知正数最多拿1个,如果正数的最小值大于负数和0之间差值的最大值,那么就可以取那个最小的正数,否则不能取正数,还需判断一下ans0=0|ans1=0|ans2=0的情况即可得出答案。

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#define INF 1e9
#define ll long long
using namespace std;
const int N=100005;
ll a[N];
int main()
{
    ios_base::sync_with_stdio(false);
    ll t,n;
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=0;i<n;i++)
            cin>>a[i];
        sort(a,a+n);
        vector<ll>vc;
        ll min1=1e12,min2=1e12,min3=1e12,ans0=0,ans1=0,ans2=0;
        for(int i=0;i<n;i++)
        {
            if(a[i]<0){
                ans0++;
                //min1=min(0-a[i],min1);
                vc.push_back(a[i]);
            }
            else if(a[i]==0)
                ans1++;

            else{
                min2=min(min2,a[i]);
                ans2++;
            }
        }
        if(ans1)
            vc.push_back(0);
        int len=vc.size();
        if(len>=2)
        {
            for(int i=1;i<len;i++)
            {
                //cout<<min3<<endl;
                min3=min(min3,vc[i]-vc[i-1]);

            }
        }
        if(ans1>=2)
            cout<<ans0+ans1<<endl;
        //else if(ans1>=2&&ans2)
            //cout<<ans1+1<<endl;
        else
        {
            if(ans1&&ans2)
            {
                if(!ans0)
                    cout<<2<<endl;
                else
                {
                    //cout<<min3<<' '<<min2<<endl;
                    if(min3>=min2)
                        cout<<ans0+2<<endl;
                    else
                        cout<<ans0+1<<endl;
                }
            }
            else if(ans1)
            {
                cout<<ans0+ans1<<endl;
            }
            else if(ans2)
            {
                if(!ans0)
                    cout<<1<<endl;
                else
                {
                    if(min3>=min2)
                        cout<<ans0+1<<endl;
                    else
                        cout<<ans0<<endl;
                }
            }
            else
                cout<<ans0<<endl;
        }

    }
    return 0;
}

C

题意:每个顶点i具有一个取值范围[li,ri],共有n-1条边,所有点连成一棵树,计算所有点取值后之间最大差值的和。

题解:对于每个顶点av∈[lv,rv],设p为与v相邻的顶点u的数量,使得au> av,q为与v相邻的顶点u的数量,使得au <av

p>q av=lv可得结果

p<q av=rv可得结果

p=q av=lv|rv可得结果

可用树型dp,从第一个点计算每个连接点的取值,一直往叶子结点以下

av=lv,dp[v][0]代表连接点的最大差值和

av=rv,dp[v][1]代表连接点的最大差值和

u为与v连接的点

dp[v][0]+=max(dp[u][0]+abs(l[v]-l[u]),dp[u][1]+abs(l[v]-r[u]))

dp[v][1]+=max(dp[u][0]+abs(r[v]-l[u]),dp[u][1]+abs(r[v]-r[u]))

因为是从顶点1开始往后递归的,所以答案很明显是max(dp[1][0],dp[1][1])。

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#define INF 1e9
#define ll long long
using namespace std;
const int N=100005;
int l[N],r[N];
ll dp[N][2];
vector<int>G[N];
void dfs(int v,int p)
{
    dp[v][0]=dp[v][1]=0;
    for(int i=0;i<G[v].size();i++)
    {
        int u=G[v][i];
        if(u==p)
            continue;
        dfs(u,v);
        dp[v][0]+=max(dp[u][0]+abs(l[v]-l[u]),dp[u][1]+abs(l[v]-r[u]));
        dp[v][1]+=max(dp[u][0]+abs(r[v]-l[u]),dp[u][1]+abs(r[v]-r[u]));
    }
}
int main()
{
    ios_base::sync_with_stdio(false);
    int t,n,u,v;
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>l[i]>>r[i];
            G[i].clear();
        }
        for(int i=1;i<n;i++)
        {
            cin>>u>>v;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1,0);
        cout<<max(dp[1][0],dp[1][1])<<endl;
    }
    return 0;
}

D

题意:在[0,2n]的数轴上要求任意两个点对A,B,使得length(A)=length(B)或者A包含于B

题解:线性dp,

包含情况:当点对[1,2*i]连上,中间[2,2*i-1]就可以随意按规则选取,即为dp[i-1],当点对[1,2*i-1],[2,2*i]连上,中间[3,2*i-2]就可以随意选取,即为dp[i-2],以此类推

等长情况:可以将2*n进行等分即为等长,那么只需求出n的正约数个数就可确定划分种类

线性方程dp[i]=(dp[1]+...+dp[i-1])+v[i](i的正约数个数)

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#define INF 1e9
#define mod 998244353
#define ll long long
using namespace std;
const int N=1000005;
int n,dp[N],s;
int main()
{
    ios_base::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j+=i)
            dp[j]++;
    s=0;
    for(int i=1;i<=n;i++)
    {
        dp[i]=(dp[i]+s)%mod;
        s=(s+dp[i])%mod;
    }
    cout<<dp[n]<<endl;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值