Codeforces Round #722 (Div. 2)

比赛链接

A. Eshag Loves Big Arrays(贪心)

大致题意:一个数组a有n个整数,你能够对数组进行任意次数的以下操作:
从数组中挑出几个数字,求出平均数,再删除这几个数字中大于平均数的数字。
求出最多能删除多少个数字?

典型的贪心,既然要删除大于我们挑出数字平均数的数字,而且要多删除几个,那么我们知道平均数是在最大值和最小值之间的,要尽量地多删除数字,就需要平均数尽量地小,那就干脆挑出最小一个的数字,去删除比它大的数字就行了,原理是:挑出两个数字,一定会删除大的那个数字

#include <bits/stdc++.h>
using namespace std;
int a[110];
int main(void)
{
    int t;
    cin>>t;
    while(t--)
    {
        int minn=110,ans=0,n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            minn=min(minn,a[i]);
        }
        for(int i=1;i<=n;i++)
        {
            if(a[i]>minn)
                ans++;
        }
        cout<<ans<<endl;
    }
    return 0;
}

B. Sifid and Strange Subsequences
题目大意:strange数组:长度为n, M A X MAX MAX为其数组的最大值,任意两个数字 a i a_i ai a j a_j aj(1<=i<j<=n), ∣ a i − a j ∣ > = M A X |a_i-a_j|>=MAX aiaj>=MAX

接下来给一个t是这是数据组数,每一次n个数字,求这个数组中最多有多少个数字可以组成strange数组。

接下来就要利用,两者差的绝对值的性质了,
如果两个数都是正数, ∣ a i − a j ∣ < M A X |a_i-a_j|<MAX aiaj<MAX,相当于 ∣ a i − a j ∣ |a_i-a_j| aiaj等于大的数减去小的数,那么strange数组不可可能有两个正数
如果两个数小于等于零, ∣ a i − a j ∣ > = M A X |a_i-a_j|>=MAX aiaj>=MAX必定成立, ∣ a i − a j ∣ > = 0 |a_i-a_j|>=0 aiaj>=0, M A X < = 0 MAX<=0 MAX<=0,所以,strange数组中可以有任意个小于等于零的数
如果数组中有一个整数,那么只需要在小于等于0的数当中,满足 ∣ a i − a j ∣ > = M A X |a_i-a_j|>=MAX aiaj>=MAX即可,(一正一负的情况必定成立,只需考虑小于等于0的数),即 ∣ a i − a j ∣ > = 这 个 正 数 |a_i-a_j|>=这个正数 aiaj>=,要这个条件尽量成立,这个正数要尽量地小,我们就取最小的那个正数(这样成立的几率最大)。
算法归纳一下就是:记录小于等于0的数和最小的正数,对小于等于进行排序的数,对每个相邻的数,取差值的绝对值,如果有小于等于的正数的,就只输出小于等于0的个数,如果没有就加上1再输出。

#include <bits/stdc++.h>
using namespace std;
int a[100005];
#define MAX 1000000001
int main(void)
{
    int t;
    cin>>t;
    while(t--)
    {
        int num1=0,minz=MAX,n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            int m;
            cin>>m;
            if(m>0)
            {
                minz=min(minz,m);
            }
            if(m<=0)
            {
                a[++num1]=m;
            }
        }
        if(minz==MAX)//这里一定要特判,否则后面会出错,而且可以加快速度
        {
            cout<<n<<endl;
            continue;
        }
        sort(a+1,a+1+num1);
        bool flag=true;
        for(int i=2;i<=num1;i++)
        {
            if(abs(a[i]-a[i-1])<minz)
            {
                flag=false;
                break;
            }
        }
        if(flag)
        {
            num1++;
        }
        cout<<num1<<endl;
    }
    return 0;
}

C题就不更了,树形DP直接裂开

D. Kavi on Pairing Duty(区间DP)
题目大意:给你一个n,表示有2n个点,按要求对这些点进行两两配对,将两点连成线段,
要么线段之间长度相等,要么线段有包含关系
在这里插入图片描述

求这2n个点配对的方案数。

设一个数组dp[i],表示2i个点的方案数,
我们以长度为n来连接端点,就有2*(n-1)个端点在中间连不上,则方案数为dp[n-1]
我们以长度为n-1来连接端点,就有2*(n-2)个端点在中间连不上,则方案数为dp[n-2]
我们以长度为n-2来连接端点,就有2*(n-3)个端点在中间连不上,则方案数为dp[n-3]
依次类推,
直到以长度为n来连接端点,我们就会发现所有的点都能连上,方案数为dp[0]=1。
如果我们进一步地缩短线段长度,就会发现,有时候端点能全部连上,有时候不能,
能全部连上的时候,线段的长度为n的因数,那是因为有2n个端点,如果长度不是n的因数的话,必定会有余下的端点。
那么状态转移方程就出来了。
d p [ i ] = ∑ j = 0 i − 1 d p [ j ] + s i z [ i ] − 1 dp[i]=\sum_{j=0}^{i-1} dp[j]+siz[i]-1 dp[i]=j=0i1dp[j]+siz[i]1
siz[i]为i的因数个数,由于dp[0]的时候加了一次(长度为i的时候),就要减去1。

#include <bits/stdc++.h>
using namespace std;
#define MAX 1000005
#define mod 998244353
int siz[MAX];
int dp[MAX];
int sum[MAX];
int main(void)
{
    dp[0]=1;
    sum[0]=1;
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j<=n;j+=i)
        {
            siz[j]++;
        }
    }
    for(int i=1;i<=n;i++)
    {
        dp[i]=(sum[i-1]+siz[i]-1)%mod;
        sum[i]=(dp[i]+sum[i-1])%mod;
    }
    cout<<dp[n];
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值