Codeforce 321DIV2 ABCD

本文解析了四道经典算法题目,包括最长上升序列、集合幸福值最大化、树形结构中特定路径计数及菜品选择优化问题。通过具体示例介绍了如何使用暴力搜索、排序加前缀和、深度优先搜索及状态压缩动态规划等方法解决这些问题。

A.

题意:找到一个最长上升序列。

解法:最最最最暴力。。

#include <bits/stdc++.h>


#define LOCAL
#define ll  long long
#define lll unsigned long long
#define MAX 1000009
#define eps 1e-8
#define INF 0x7fffffff
#define mod 1000000007


using namespace std;


int a[MAX];


int main()
{


    int n;
    cin>>n;
    int sum = 1;
    int _max = -1;
    cin>>a[0];
    int k = a[0];
    for(int i = 1;i<n;i++)
    {
        cin>>a[i];
        if(a[i]>=k)
        {
            sum++;
        }
        else
        {
            _max = max(_max, sum);
            sum = 1;
        }
        k = a[i];
    }
    _max = max(_max, sum);
    cout<<_max<<endl;
    return 0;
}

B.

题意:找到任意元素之间绝对值小于d的集合的幸福值和的最大值。

解法:把m从小到大排序,然后二分查找 m[i] 和 m[i] + d - 1的位置,然后维护个前缀和,这样就能快速找到区间和了。

写的时候注意边界的处理


#include <bits/stdc++.h>


#define LOCAL
#define ll  long long
#define lll unsigned long long
#define MAX 1000009
#define eps 1e-8
#define INF 0x7fffffff
#define mod 1000000007


using namespace std;


struct node{
    ll m,s;
}p[MAX];
bool cmp(node a,node b)
{
    return a.m < b.m;
}
ll sum[MAX];
ll x[MAX];


int main()
{
    int n,d;
    while(~scanf("%d%d",&n,&d))
    {
        for(int i = 0;i<n;i++)
        {
            cin>>p[i].m>>p[i].s;
        }
        sort(p,p+n,cmp);
        sum[0] = p[0].s;
        for(int i = 1;i<n;i++)
        {
            sum[i] = sum[i - 1] + p[i].s;
        }
        for(int i = 0;i<n;i++)
        {
            x[i] = p[i].m;
        }
        ll _max = -1;
        for(int i = 0;i<n;i++)
        {
            int pos1 = lower_bound(x,x+n,p[i].m) - x;
            int pos2 = upper_bound(x,x+n,p[i].m + d - 1) - x;
            //cout<<pos1<<" "<<pos2 - 1<<endl;
            if(pos1==pos2-1)
            {
                _max = max(_max,p[pos1].s);
            }
            else
            {
                if(pos1 == 0)
                     _max = max(_max,sum[pos2 - 1]);
                else
                    _max = max(_max,sum[pos2 - 1] - sum[pos1 - 1]);
            }
        }
        printf("%lld\n",_max);
    }
    return 0;

C.

题意:实质是从根节点出发到叶子节点的路径上,最长连续被标记的长度小于等于d的叶子节点数

解法:DFS 三个参数 当前结点 当前节点的父亲节点 最长连续被标记的长度

没有被标记的就清空


#include <bits/stdc++.h>


#define LOCAL
#define ll  long long
#define lll unsigned long long
#define MAX 1000009
#define eps 1e-9
#define INF 0x7fffffff
#define mod 1000000007


using namespace std;


struct node
{
    int num;
    int to;
};
vector<int>g[MAX];
int vis[MAX];
int num[MAX];
int ans;
int n,d;


void dfs(int u,int sum,int fu)
{
   if(sum > d)
    return ;
   if(g[u].size()==1&&u!=1)
       ans++;
   for(int i = 0;i<g[u].size();i++)
   {
       int v = g[u][i];
       if(v==fu)continue;
       if(vis[v])
        dfs(v,sum+1,u);
       else
        dfs(v,0,u);
   }
}


int main()
{
    cin>>n>>d;
    memset(vis,0,sizeof(vis));
    for(int i = 1; i<=n; i++)
    {
        cin>>vis[i];
    }
    for(int i = 1; i<n; i++)
    {
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    ans = 0;
    dfs(1,vis[1],-1);
    printf("%d\n",ans);
    return 0;

D.

题意:n到菜选m道菜,且先选i 后选j 会额外得到 use[i][j]的奖励,求最大值

解法:状态压缩DP 第一维选取了哪些菜,第二维,最后一次选的菜是什么

#include <bits/stdc++.h>


#define LOCAL
#define ll  long long
#define lll unsigned long long
#define MAX 1000009
#define eps 1e-8
#define INF 0x7fffffff
#define mod 1000000007


using namespace std;


ll dp[1<<18][18];//第一维选取了哪些菜,第二维,最后一次选的菜是什么
ll a[50];
ll use[50][50];


int main()
{
    int n,m,k;
    ll u,v,w;
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        for(int i = 0; i<n; i++) scanf("%lld",&a[i]);
        for(int i = 0; i<k; i++)
        {
            scanf("%lld%lld%lld",&u,&v,&w);
            --u;
            --v;
            use[u][v] = w;
        }
        for(int i = 0; i<n; i++)
        {
            dp[1<<i][i] = a[i];
        }
        for(int Status = 1; Status<(1<<n); Status++)
        {
            for(int i = 0; i<n; i++)
            {
                if(!(Status&(1<<i)))
                {
                    for(int j = 0; j<n; j++)
                    {
                        if((Status&(1<<j)))
                        {
                            dp[Status|(1<<i)][i] = max(dp[Status|(1<<i)][i],dp[Status][j] + a[i] + use[j][i]);
                        }
                    }
                }
            }
        }
        ll _max = 0;
        for(int Status = 0; Status<(1<<n); Status++)
        {
            int cnt = 0;
            for(int i = 0; i<n; i++)
            {
                if(Status&(1<<i))
                {
                    cnt++;
                }
            }
            if(cnt==m)
            {
                for(int i = 0; i<n; i++)
                {
                    _max = max(_max,dp[Status][i]);
                }
            }
        }
        printf("%lld\n",_max);
    }
    return 0;
}

### Codeforces 题目难度分布及评级标准 Codeforces 的题目难度范围广泛,涵盖了从新手到专家级别的各种挑战[^1]。该平台通过细致的分层机制来区分不同难度等级的问题,使得每位参赛者都能找到适合自己水平的任务。 #### 评分体系概述 Codeforces 使用基于积分制的评价系统,其中每道题都有一个对应的分数(rating),用于表示其相对难易程度。较低的 rating 表明这是一道较为简单的题目;而较高的 rating 则意味着更高的复杂性和解决难度。通常情况下: - **简单题**:Rating 小于等于 1200 分 - **中等偏难题**:Rating 范围大约在 1600 至 2000 分之间 - **困难题**:Rating 大于等于 2400 分 这些数值并不是固定的界限,而是根据社区反馈以及比赛实际情况调整的结果。 #### Divisions 和 Contest Types 为了更好地适应不同程度的学习者和技术爱好者的需求,Codeforces 提供了多种类型的竞赛活动,比如 Division 1, Division 2, Division 3 及 Division 4 等不同类型的比赛[^2]。每个 division 对应着不同的最低准入门槛——即参与者应该具备的基础能力或经验水平。例如,在更高级别的比赛中会遇到更多高难度的问题。 #### 技术领域覆盖 平台上发布的题目不仅限于单一的技术方向,还涉及到多个计算机科学的重要分支,如贪心算法、动态规划、图论等领域。这种多样性有助于全面锻炼编程技巧并促进跨学科思维的发展。 ```python # 示例 Python 代码片段展示如何获取某场比赛的信息 import requests def get_contest_info(contest_id): url = f"https://codeforces.com/api/contest.standings?contestId={contest_id}&from=1&count=1" response = requests.get(url).json() if 'result' not in response or 'problems' not in response['result']: return None problems = response['result']['problems'] for problem in problems: print(f"{problem['index']}: {problem['name']} - Rating: {problem.get('rating', 'N/A')}") get_contest_info(1669) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值