2018HNCPC自我补题

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;
}

猜你喜欢

转载自blog.csdn.net/qq_35577488/article/details/109012536