Codeforces Round #831 (Div. 1 + Div. 2) E. Hanging Hearts

 

 

翻译:

 

Pak Chanek有𝑛空白心形卡片。卡片1直接贴在墙上,而其他卡片则通过一根绳子恰好挂在另一张卡片上。具体地说,卡𝑖(𝑖> 1)是挂卡𝑝𝑖(𝑝𝑖<𝑖)。

一开始,Pak Chanek必须在每张卡片上写一个整数。他通过选择[1,2,…,𝑛]的任何排列𝑎来做到这一点。那么,写在卡片𝑖上的号码就是𝑎𝑖。

之后,Pak Chanek必须执行以下操作𝑛次,同时保持序列𝑠(初始值为空):

选择一张卡片𝑥,这样就不会有其他卡片挂在上面。
把写在卡片𝑥上的号码加在𝑠后面。
当𝑥≠1且𝑝𝑥卡片上的数字大于𝑥卡片上的数字时,请将𝑝𝑥卡片上的数字替换为𝑥卡片上的数字。
删除卡𝑥。
之后,Pak Chanek将有一个包含𝑛元素的序列𝑠。如果Pak Chanek以最优方式完成所有步骤,𝑠的最长非递减子序列†的最大长度是多少?

†数列𝑏是数列𝑐的子数列,如果𝑏可以通过删除几个(可能是零或全部)元素从𝑐中得到。例如,[3,1]是[3,2,1]、[4,3,1]和[3,1]的子序列,但不是[1,3,3,7]和[3,10,4]。

输入
第一行包含单个整数𝑛(2≤𝑛≤105)—心形卡片的数量。

第二行包含𝑛−1个整数𝑝2,𝑝3,…,𝑝𝑛(1≤𝑝𝑖<𝑖),描述每张卡片挂在哪张卡片上。

输出
打印单个整数——如果Pak Chanek以最优方式完成所有步骤,则输出𝑠的最长非递减子序列的最大长度。

例子
inputCopy
6
1 2 1 4 2
outputCopy
4
inputCopy
2
1
outputCopy
2
请注意
下面是第一个例子中卡片的结构。

Pak Chanek可以选择排列𝑎=[1,5,4,3,2,6]。

让𝑤𝑖是写在卡片𝑖上的数字。最初,𝑤𝑖=𝑎𝑖。Pak Chanek可以依次进行以下操作:

选择卡5。在“𝑠”后面添加“𝑤5=2”。当输入𝑤4>𝑤5时,𝑤4的值变为2。删除卡5。执行该操作后,系统显示为𝑠=[2]。
选择卡6。在“𝑠”后面添加“𝑤6=6”。当𝑤2≤𝑤6时,𝑤2的值保持不变。删除卡6。该操作完成后,输出结果为𝑠=[2,6]。
选择卡4。在“𝑠”后面添加“𝑤4=2”。当𝑤1≤𝑤4时,𝑤1的值保持不变。删除卡4。该操作完成后,输出结果为𝑠=[2,6,2]。
选择卡3。在“𝑠”后面添加“𝑤3=4”。当输入𝑤2>𝑤3时,𝑤2的值变为4。删除卡3。该操作完成后,𝑠=[2,6,2,4]。
选择卡2。在“𝑠”后面添加“𝑤2=4”。当𝑤1≤𝑤2时,𝑤1的值保持不变。删除卡2。该操作完成后,𝑠=[2,6,2,4,4]。
选择卡1。在“𝑠”后面添加“𝑤1=1”。删除卡1。该操作完成后,𝑠=[2,6,2,4,4,1]。
𝑠=[2,6,2,4,4,1]的最长非递减子序列之一是[2,2,4,4]。因此,𝑠的最长非递减子序列的长度为4。可以证明,这确实是可能的最大长度。

代码实现:

#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include <stdio.h>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<tuple>
#include<numeric>
using namespace::std;
typedef long long  ll;
inline __int128 read(){
    __int128 x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
inline void print(__int128 x){
    if(x < 0){
        putchar('-');
        x = -x;
    }
    if(x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}
int n,m;
vector<int> q[100005];
ll dp[100005][3];
void dfs(int x,int y){
    dp[x][1]=1;
    dp[x][0]=0;
    for (auto k:q[x]) {
        dfs(k,x);
        dp[x][1]=max(dp[k][1]+1, dp[x][1]);
        dp[x][0]+=max(dp[k][0],dp[k][1]);
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(); cout.tie();
    cin>>n;
    for (int i =1; i<n; i++) {
        cin>>m;
        q[m].push_back(i+1);
    }
    dfs(1,0);
    printf("%lld\n",max(dp[1][1], dp[1][0]));
    return 0;
}
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值