2018HNCPC自我补题

2023大厂真题提交网址(含题解):

www.CodeFun2000.com(http://101.43.147.120/)

最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
在这里插入图片描述

B.打表找规律

这里比赛的时候蠢了。其实一眼发现是平方数.至于(2000,2000)这个数据不是平方数。是因为他取过模了。。这里没想通导致自己蠢了.

H.线段树,思维

一眼线段树…题目说明了询问区间长度 ≤ \leq 3.我们应该要充分利用这个性质。不难发现,我们可以将左右端点分别维护.然后用简单的容斥去计算:

完全包含区间 [ L , R ] [L,R] [L,R]的线段个数 = 总线段个数 - [右端点 < < < R的线段]个数 - [左端点 > > > L的线段]个数 + 完全在区间 ( L , R ) (L,R) (L,R)中的线段个数.

前三项计算完,完全在区间 ( L , R ) (L,R) (L,R)中的线段个数会被减两次。所以需要加一下。而区间长度 ≤ \leq 3 ,我们完全可以存数组下来求一求.

我比赛的时候多组输入少写一个 '~'导致超时然后XJB交了8发才发现。。。离谱了。重回小学了.

J.dfs, 计数

刚才花20分钟补了一下。难度对标小白月赛。。感觉榜被带偏了。

这张图的特性:每个点有且仅有1个入度。并且从根节点到每个点的路径唯一.

子问题:给你一个序列 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an a i ∈ [ 1 , n ] a_i \in [1,n] ai[1,n]问你有多少个不同的有序二元组 ( x , y ) (x,y) (x,y).

O ( n 2 ) O(n^2) O(n2)的做法就不说了,考虑 O ( n ) O(n) O(n)的做法:

考虑新增一个元素 a i a_i ai。它对答案的贡献受限于前一个 a i a_i ai出现的位置。

例如: 4,1,2,3,4 和 1,2,4,3,4 和 1,2,3,4,4 。这几组4对答案的贡献是不一样的.

自然我们想到记录上一次 a i a_i ai出现时,前缀中不同的数的个数cnt1。假设当前的前缀中不同的数的个数为cnt2.那么当前 a i a_i ai对答案的贡献为: c n t 2 − c n t 1 cnt2-cnt1 cnt2cnt1

放到图上也是一样,跑个dfs.记得dfs完某个节点撤销状态即可.

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
const int maxn = 1e5 + 5;
vector<int> E[maxn];
ll ans[maxn] , book[maxn] , off[maxn] , cnt = 0;
int a[maxn];
void dfs (int u , int fa)
{
    ans[u] = ans[fa] + cnt - off[a[u]];
    int o = off[a[u]];
    off[a[u]] = cnt;
    if (book[a[u]] == 0) cnt++;
    book[a[u]]++;
    for (auto v : E[u]){
        if (v == fa) continue;
        dfs (v , u);
    }
    if (book[a[u]] == 1) cnt--;
    book[a[u]]--;
    off[a[u]] = o;
    return ;
}
int main()
{
    ios::sync_with_stdio(false);
    int n;
    while(cin >> n){
        cnt = 0;
        for (int i = 0 ; i <= n ; i++){
            book[i] = ans[i] = off[i] = 0;
            E[i].clear();
        }
        for (int i = 2 ; i <= n ; i++){
            int x; cin >> x;
            E[x].pb(i);
        }
        for (int i = 1 ; i <= n ; i++)
            cin >> a[i];
        dfs (1 , 0);
        for (int i = 2 ; i <= n ; i++){
            cout << ans[i] << endl;
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值