• NOI 模拟赛


    T1 binary

    求有多少不同构的二叉树最长链为 $n$,答案对 $10^k$ 取模

    $n leq 200000,k leq 64$

    sol:

    首先转化一下,原题要求的链长是边数,转换成点数好做一点,把 n+1 即可

    记 $f_{(i,0)}$ 表示最大深度为 $i$,当前没有长为 $n$ 的链,有多少不同构二叉树

     $f_{(i,1)}$ 表示最大深度为 $i$,当前有长为 $n$ 的链,有多少不同构二叉树

    因为只有二叉,考虑将两个二叉树的根向上连出一个新点,转移答案

    枚举这个新的二叉树深度,显然原来两个二叉树至少有一个深度为 $i-1$

    如果新的二叉树有长为 $n$ 的链,分两种情况

    1.原来有一个二叉树有长为 $n$ 的链,不妨设在左边,这样只要保证右边跟左边拼出来的链长度不超过 $n$ 就可以了,显然右边深度不超过 $min(n-i,i-1)$,因为左右对称,要乘 2 ,之后因为乘了 2 ,要减去左右两边深度一样的情况,而这种情况在 $n-i<i-1$ 的时候是不存在的

    2.两边都没有长为 $n$ 的链,那就一定要拼出来一条长度为 $n$ 的链,左边是 $i-1$ ,右边就是 $n-i$ ,注意 $i-1$ 要大于等于 $n-i$,等于的时候只有一种情况,不等于可以交换左右儿子

    没有的话,保证拼不出来即可,也就是如果左边是 $i-1$ ,右边的上界就是 $min(n-i-1,i-1)$ ,还是可以交换左右,注意当 $i-1 leq n-i-1$ 的时候要排除两边一样的情况

    前缀和优化 dp 即可,然后因为 k 是 64 ,需要高精度

    但我不想写

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    inline LL read()
    {
        LL x = 0,f = 1;char ch = getchar();
        for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f;
        for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
        return x * f;
    }
    const int maxn = 200010;
    LL n,k,mod = 1;
    LL f[maxn][2],sum[maxn][2];
    namespace subtask_low
    {
        int main()
        {
            for(int i=1;i<=k;i++)mod *= 10;
            f[0][0] = 1;
            sum[0][0] = 1;
            for(LL i=1;i<=n;i++)
            {
                if(i != n)f[i][0] = (f[i][0] + (2 * f[i - 1][0] * sum[min(n - i - 1,i - 1)][0]) % mod) % mod;
                if((i - 1) < (n - i))f[i][0] = (f[i][0] + mod - ((f[i - 1][0] * f[i - 1][0]) % mod)) % mod;
                
                f[i][1] = (f[i][1] + (2 * (f[i - 1][1] * ((sum[min(n-i,i-1)][0] + sum[min(n-i,i-1)][1]) % mod)) % mod) % mod) % mod;
                if((i - 1) <= (n - i))f[i][1] = (f[i][1] + mod - (f[i - 1][1] * f[i - 1][1] % mod)) % mod;
                if((i - 1) >= (n - i))f[i][1] = (f[i][1] + (2 * f[i - 1][0] * f[n - i][0]) % mod) % mod;
                if((i - 1) == (n - i))f[i][1] = (f[i][1] + mod - ((f[i - 1][0] * f[n - i][0]) % mod)) % mod;
                
                sum[i][0] = (sum[i - 1][0] + f[i][0]) % mod;
                sum[i][1] = (sum[i - 1][1] + f[i][1]) % mod;
                //cout << f[i][0] << " " << f[i][1] << endl;
            }
            cout << sum[n][1] << endl;
            return 0;
        }
    }
    int main()
    {
        freopen("binary.in","r",stdin);
        freopen("binary.out","w",stdout);
        n = read() + 1,k = read();
        subtask_low::main();
    }
    T1

    T2 sort

    求一个有向图字典序最小的拓扑序和字典序最大的拓扑序

    $n leq 200000,m=n$

    sol:

    送分题,字典序最大的拓扑序直接用个堆,字典序最小的就建反图用个堆

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    inline int read()
    {
        int x = 0,f = 1;char ch = getchar();
        for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f;
        for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
        return x * f;
    }
    const int maxn = 200010;
    int n,a[maxn];
    priority_queue<int> q;
    int first[maxn],to[maxn << 1],nx[maxn << 1],cnt,ind[maxn],ans[maxn],pnt,reh[maxn];
    inline void add(int u,int v){to[++cnt] = v;nx[cnt] = first[u];first[u] = cnt;}
    int main()
    {
        freopen("sort.in","r",stdin);
        freopen("sort.out","w",stdout);
        n = read();
        for(int i=1;i<=n;i++)a[i] = read();
        
        memset(ans,0,sizeof(ans));memset(reh,0,sizeof(reh));pnt = 0;
        
        for(int i=1;i<=n;i++)if(a[i]){add(i,a[i]);ind[a[i]]++;}
        for(int i=1;i<=n;i++)if(ind[i] == 0)q.push(i);
        while(!q.empty())
        {
            int now = q.top();q.pop();
            //cout << now << " ";
            ans[++pnt] = now;
            for(int i=first[now];i;i=nx[i]){ind[to[i]]--;if(ind[to[i]] == 0)q.push(to[i]);}
        }
        for(int i=1;i<=n;i++)reh[ans[n - i + 1]] = i;
        for(int i=1;i<=n;i++)cout << reh[i] << " ";
        cout << endl;
        memset(first,0,sizeof(first));cnt = 0;memset(ind,0,sizeof(ind));
        memset(ans,0,sizeof(ans));memset(reh,0,sizeof(reh));pnt = 0;
        
        for(int i=1;i<=n;i++)if(a[i]){add(a[i],i);ind[i]++;}
        for(int i=1;i<=n;i++)if(ind[i] == 0)q.push(i);
        while(!q.empty())
        {
            int now = q.top();q.pop();
        //    cout << now << " ";
            ans[++pnt] = now;
            for(int i=first[now];i;i=nx[i])
            {
                ind[to[i]]--;
                if(ind[to[i]] == 0)q.push(to[i]);
            }
        }
        for(int i=1;i<=n;i++)reh[ans[i]] = i;
        for(int i=1;i<=n;i++)cout << reh[i] << " ";
        cout << endl;
        //for(int i=pnt;i;i--)cout << ans[i] << " ";
        //cout << endl;
        memset(first,0,sizeof(first));cnt = 0;memset(ind,0,sizeof(ind));
    }
    T2

    T3 mst

    $q$ 次询问图中删掉一条边的最小生成树边权和,或者输出 "Not Connected"

    $n,m,q leq 100000$

    sol:

    每条树边记录一下能覆盖它的非树边的最小权值

    用树剖套线段树区间修改单点查询

    #include<bits/stdc++.h>
    #define LL long long
    #define maxn 250010
    #define lson l, mid, x << 1
    #define rson mid + 1, r, x << 1 | 1
    using namespace std;
    inline int read()
    {
        int x = 0,f = 1;char ch = getchar();
        for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f;
        for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
        return x * f;
    }
    struct data
    {
        int x, y, z, id;
        bool vis;
    } a[maxn << 1];
    int f[maxn], head[maxn], to[maxn << 1], val[maxn << 1], nx[maxn << 1], cnt, reh[maxn << 1], fa[maxn], deep[maxn], si[maxn], bl[maxn],
        pos[maxn], tot, mn[maxn << 2], n;
    bool cmp1(const data &a, const data &b) { return a.z < b.z; }
    bool cmp2(const data &a, const data &b) { return a.id < b.id; }
    int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }
    void add(int x, int y, int z) { to[++cnt] = y, val[cnt] = z, nx[cnt] = head[x], head[x] = cnt; }
    void dfs1(int x)
    {
        int i;
        si[x] = 1;
        for (i = head[x]; i; i = nx[i])
            if (to[i] != fa[x])
                fa[to[i]] = x, deep[to[i]] = deep[x] + 1, reh[val[i]] = to[i], dfs1(to[i]), si[x] += si[to[i]];
    }
    void dfs2(int x, int c)
    {
        int i, k = 0;
        bl[x] = c, pos[x] = ++tot;
        for (i = head[x]; i; i = nx[i])
            if (to[i] != fa[x] && si[to[i]] > si[k])
                k = to[i];
        if (k)
        {
            dfs2(k, c);
            for (i = head[x]; i; i = nx[i])
                if (to[i] != fa[x] && to[i] != k)
                    dfs2(to[i], to[i]);
        }
    }
    void update(int b, int e, int a, int l, int r, int x)
    {
        if (b <= l && r <= e)
        {
            mn[x] = min(mn[x], a);
            return;
        }
        int mid = (l + r) >> 1;
        if (b <= mid)
            update(b, e, a, lson);
        if (e > mid)
            update(b, e, a, rson);
    }
    int query(int p, int l, int r, int x)
    {
        if (l == r)
            return mn[x];
        int mid = (l + r) >> 1;
        if (p <= mid)
            return min(mn[x], query(p, lson));
        else
            return min(mn[x], query(p, rson));
    }
    void modify(int x, int y, int v)
    {
        while (bl[x] != bl[y])
        {
            if (deep[bl[x]] < deep[bl[y]])
                swap(x, y);
            update(pos[bl[x]], pos[x], v, 1, n, 1), x = fa[bl[x]];
        }
        if (deep[x] > deep[y])
            swap(x, y);
        if (x != y)
            update(pos[x] + 1, pos[y], v, 1, n, 1);
    }
    signed main()
    {
        freopen("mst.in","r",stdin);
        freopen("mst.out","w",stdout);
        int m, q, x, v, c = 0;
        LL sum = 0;
        n = read(),m = read();
        for (int i = 1; i <= m; i++) a[i].x = read(), a[i].y = read(), a[i].z = read(), a[i].id = i;
        sort(a + 1, a + m + 1, cmp1);
        for (int i = 1; i <= n; i++) f[i] = i;
        for (int i = 1; i <= m; i++)
            if (find(a[i].x) != find(a[i].y))
                sum += a[i].z, a[i].vis = 1, add(a[i].x, a[i].y, a[i].id), add(a[i].y, a[i].x, a[i].id),
                               f[f[a[i].x]] = f[a[i].y], c++;
        if (c < n - 1)
        {
            q = read();
            while (q--) puts("Not connected");
            return 0;
        }
        dfs1(1), dfs2(1, 1);
        memset(mn, 127, sizeof(mn));
        sort(a + 1, a + m + 1, cmp2);
        for (int i = 1; i <= m; i++)
            if (!a[i].vis)
                modify(a[i].x, a[i].y, a[i].z);
        q = read();
        while (q--)
        {
            x = read();
            if (!a[x].vis)
                printf("%lld
    ", sum);
            else
            {
                v = query(pos[reh[x]], 1, n, 1);
                if (v == 2139062143)
                    puts("Not connected");
                else
                    printf("%lld
    ", sum - a[x].z + v);
            }
        }
        return 0;
    }
    T3
  • 相关阅读:
    关于OC中.m文件下实现私有变量的方法,在.h文件下实现公有变量的方法
    mac中安装homebrew
    ios架构
    github命令记录
    Unity 游戏框架搭建 MonoBehaviour单例的模板
    Unity 游戏框架搭建 单例的模板
    unity 单列
    简单工厂与工厂
    NGUI动态播放视频
    在一个GameObject上进行多个AudioSource的控制
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/10260663.html
Copyright © 2020-2023  润新知