zoukankan      html  css  js  c++  java
  • HZOI0727爆零赛

    写在前面:

    要吃早饭,不然头晕手抖不想写暴力分


    考试概况:

    T1 : 数学原根优化矩阵BOOST期望DP  pts:0

    T2 : 树形DP,推式子大题  pts:0

    T3 : 简单组数,DP  pts:80

    sum:80  rank:26

    其实T1能打10分,T2能打30分,但是头疼+牙周炎+手抖,打完T3就没心情了


    考试流程:

    看T1,原根?期望?走人

    看T2,树形DP?没学过没写过,还要写DFS?我好懒啊放过我吧

    看T3,组数?我好像还记得点,打吧,打点别爆零就行

    打了2.5h发现自己好像能吃好多分.....打到typ=3不会,dp走人

    然后回去翻了翻前面的题,一个都不想写,头疼睡了

    考完试之后听HZ大佬吴迪说自己最后30min快速RUSHT1拿了50pts,瞬间感觉心态挺重要

    但是什么都不会心态又有什么用呢


    T1:随(rand)

    期望绝赞不会中

    以前打的期望题没一个能套上去的,我自闭了

    下来题解TM看不懂一个字,都是啥啊

    考场上看到有个n=1开开心心打个快速幂,但是好像理解错题意连10pts都没有

    绝赞极度难过中


    T2:单(single)

    在套路上玩出新意的好题

    有两种情况,第二种相对恶心,先来第一种

    首先pick节点1来作为根,然后求出对于每个节点它的子树的点的权值和,

    暴力求出根的答案,然后O(n)遍历树上所有点并换根DP,可以推一个简单式子来得到每个点的答案

    对于第二种,通过儿子减父亲,可以得到 子树中的点权和 和 树上所有其他点权和 的 差,然后高斯消元

    但是蒟蒻刚才去看了隔壁大佬的博客发现好像不用高斯消元,只要大力推式子即可,

    下面部分转载自模拟赛9 SDFZ的RANK1 队爷tkj

    我们取1号节点为根。
    sum表示所有节点a值之和,size表示子树a值之和。
    我们考虑从a求b的过程,因为我们原来是换根求的b数组,所以相邻两个节点的b值相减后为sum-2sizey
    如果我们能知道sum的话所有值就能求出来了,但是要怎么求sum呢,考场上没想出来QAQ。
    总是想着把它们加起来可以搞出sum,结果不行。
    我们发现一号节点没有这个式子,所以我们把它的式子暴力写出来
    b1=∑ni=1aidepi
    我们惊奇的发现这个式子等于ni=2sizei
    减一下就出来了。
    考场上就差最后两行了,Orz

    ni=1aidepi = ni=2sizei 我跪了,我没想到

    看过别人博客之后才发觉自己的博客只有自己能看懂,但强人的博客别人也能看懂,Orz

    考场上想到没学过,学过不会背板子,背了细节调不对,人真难啊

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int MAXN = 100010;
    long long siz[MAXN],deep[MAXN],a[MAXN],b[MAXN],n,sum;
    long long lef = 0;
    struct Edge{
        int nxt,to;
    }edge[MAXN<<1];
    int head[MAXN],ectr;
    void addedge(int from,int to){
        edge[++ectr].nxt =head[from];
        head[from] = ectr;
        edge[ectr].to = to;
    }
    
    void dfs1(int x,int fa){
        deep[x] = deep[fa] + 1;
        siz[x] = a[x];
        for(int i=head[x];i;i=edge[i].nxt){
            int to = edge[i].to;
            if(to == fa) continue;
            dfs1(to,x);
            siz[x] += siz[to];
        }
    }
    
    void dfs2(int x,int fa){
        b[x] = b[fa] - 2*siz[x] + siz[1];
        for(int i=head[x];i;i=edge[i].nxt){
            if(edge[i].to == fa) continue;
            dfs2(edge[i].to,x);
        }
    }
    
    void dfs3(int x,int fa){
        lef += b[x];lef -= b[fa];
        for(int i=head[x];i;i=edge[i].nxt){
            int to = edge[i].to;
            if(to == fa) continue;
            dfs3(to ,x);
        }
    }
    
    void dfs4(int x,int fa){
        siz[x] = (sum + b[fa] - b[x]) / 2;
        for(int i=head[x];i;i=edge[i].nxt){
            int to = edge[i].to;
            if(to == fa) continue;
            dfs4(to,x);
        }
    }
    
    void dfs5(int x,int fa){
        a[x] = siz[x];
        for(int i=head[x];i;i=edge[i].nxt){
            int to = edge[i].to;
            if(to == fa) continue;
            a[x] -= siz[to];
            dfs5(to,x);
        }
    }
    
    void solve1(){
        siz[1] = a[1];
        for(int i=head[1];i;i=edge[i].nxt){
            dfs1(edge[i].to,1);
            siz[1] += siz[edge[i].to];
        }
        for(int i=1;i<=n;i++){
            b[1] += a[i] * deep[i];
        }
        for(int i=head[1];i;i=edge[i].nxt){
            dfs2(edge[i].to,1);
        }
        for(int i=1;i<=n;i++){
            cout<<b[i]<<" ";
        }
        cout<<endl;
        return;
    }
    
    void solve2(){
        for(int i=head[1];i;i=edge[i].nxt){
            int to = edge[i].to;
            dfs3(to ,1);
        }
        lef += 2*b[1];
        sum = lef / (n - 1);
        for(int i=head[1];i;i=edge[i].nxt){
            int to = edge[i].to;
            dfs4(to,1);
        }
        long long evil = 0;
        for(int i=head[1];i;i=edge[i].nxt){
            int to = edge[i].to;
            evil += siz[to];
        }
        a[1] = sum - evil;
        siz[1] = sum;
        for(int i=head[1];i;i=edge[i].nxt){
            dfs5(edge[i].to,1);
        }
        for(int i=1;i<=n;i++){
            cout<<a[i]<<" ";
        }cout<<endl;
        return;
    }
    
    void _sweep(){
        memset(head,0,sizeof head);ectr = 0;lef = 0;sum = 0;
        memset(edge,0,sizeof edge);memset(a,0,sizeof a);memset(b,0,sizeof b);
        n=0;memset(siz,0,sizeof siz);memset(deep,0,sizeof deep);
    }
    
    int main(){
        ios::sync_with_stdio(false);
        int T;
        cin>>T;
        while(T--){
            _sweep();
            cin>>n;
            for(int i=1;i<n;i++){
                int a,b;
                cin>>a>>b;
                addedge(a,b);
                addedge(b,a);
            }
            int typ;
            cin>>typ;
            if(typ == 0){
                for(int i=1;i<=n;i++){
                    cin>>a[i];
                }
                solve1();
            }
            if(typ == 1){
                for(int i=1;i<=n;i++){
                    cin>>b[i];
                }
                solve2();
            }
    
        }
        return 0;
    } 
    T2 AC代码

     T3:题(problem)

    四种情况

    第一种:简单组合问题,但莫名其妙不优化式子跑不满25pts,我只有20pts

    第二种:一眼卡特兰数,背的exgcd逆元组合数直接往上砸,拿分走人

    第三种:观察到数据范围不一样,DP之魂燃烧,写码农代码

    第四种:考场上想出来25pts然后自己否了自己,写了个10pts码农DP,后来听说是卡特兰数相乘,悔恨泪水流下来,

    wdnmd老子调了一晚上终于A了,要预处理inv和fac

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int mod = 1000000007;
    int n,typ;
    long long invv[200010],fac[200010];
    int dpx[2][2100],dpy[2][2100];
    
    long long qp(long long a,long long x){
        long long ret = 1;
        while(x){
            if(x&1) ret = (ret * a) % mod;
            a = (a * a) % mod;
            x >>= 1;
        }
        return ret;
    }
    
    void set_up(long long n){
        fac[0] = 1;
        for(int i=1;i<=n;i++){
            fac[i] = fac[i-1] * i % mod;
        }
        invv[n]=qp(fac[n],mod-2);
        for(int i=n-1;i>=0;i--){
            invv[i] = invv[i+1] * (i+1) % mod;
        }
        return;
    }
    
    long long C(long long n,long long m){
           return fac[n] * invv[n-m] % mod * invv[m] % mod;
    }
    
    long long catelan (long long n){
        return (C(2*n,n) - C(2*n,n-1) + mod) % mod;
    }
    
    int main(){
        ios::sync_with_stdio(false);
        cin>>n>>typ;
        set_up(n);
        if(typ == 0) {
            long long ans = 0;
            for(int i=0;i<=n/2;i++) {
                ans = ans + ((C(n,2*i) * C(2*i,i)) % mod + mod) * C(n-(2*i), (n-2*i)/2) % mod;
                ans %= mod;
            }
            cout<<ans<<endl;
            return 0;
        }
        if(typ == 1) {
            cout<<(long long)((C(n,n/2) - C(n,(n/2)-1)) + mod) % mod<<endl;
            return 0;
        }
        if(typ == 2){
            int del = 1010;
            dpx[0][del] = 1;
            dpy[0][del] = 1;
            for(int x=1;x<=n;x++){
                for(int j=1;j<=x;j++){
                    dpx[x&1][j+del] = dpx[(x-1)&1][j+del+1];
                    dpx[x&1][j+del] += dpx[(x-1)&1][j+del-1];
                    dpx[x&1][j+del] %= mod;
                    dpy[x&1][j+del] = dpy[(x-1)&1][j+del+1];
                    dpy[x&1][j+del] += dpy[(x-1)&1][j+del-1];
                    dpy[x&1][j+del] %= mod;
                    dpx[x&1][del-j] = dpx[(x-1)&1][del-j+1];
                    dpx[x&1][del-j] += dpx[(x-1)&1][del-j-1];
                    dpx[x&1][del-j] %= mod;
                    dpy[x&1][del-j] = dpy[(x-1)&1][del-j+1];
                    dpy[x&1][del-j] += dpy[(x-1)&1][del-j-1];
                    dpy[x&1][del-j] %= mod;
                }
                dpx[x&1][del] = dpx[(x-1)&1][del-1] + dpx[(x-1)&1][del+1];
                dpx[x&1][del] %= mod;
                dpx[x&1][del] += dpy[(x-1)&1][del-1];
                dpx[x&1][del] %= mod;
                dpx[x&1][del] += dpy[(x-1)&1][del+1];
                dpx[x&1][del] %= mod;
                dpy[x&1][del] = dpx[x&1][del];
            }
            cout<<dpx[n&1][del]<<endl;
            return 0;
        }
        if(typ == 3){
            long long ans = 0;
            for(int i=0;i<=n;i+=2){
                ans = (ans + C(n,i)*catelan(i/2)%mod*catelan((n-i)/2)%mod)%mod;
            }
            cout<<ans<<endl;
            return 0;
        }
    }
    T3 AC代码

    这次爆零获得的经验:

    1.对于一些式子特别长的题,在打式子的时候最好调用函数,好调好写,还缩短代码量,美滋滋(参考了tkj码风)

    2.耐心推一推,写一写,调一调,就能拿到分的题,还是要好好下功夫的(比如T2),下考了也要练一练

    3.进行决策,合理放弃(如T1)。


    写在最后:

    我想DKYgg了

    TAG : SIN_XIII


  • 相关阅读:
    一篇文章让你了解GC垃圾回收器
    使用SpringBoot整合ssm项目
    SpringBoot项目集成Hystrix
    50个简单易懂的经济学定律
    使用POI导出EXCEL工具类并解决导出数据量大的问题
    数据库事务的四大特性以及四种隔离级别
    简单了解Redis
    如何更规范化的编写JAVA 代码
    如何在Linux服务器上部署Mysql
    常见的数据库函数,关键字整理
  • 原文地址:https://www.cnblogs.com/SINXIII/p/11254511.html
Copyright © 2011-2022 走看看