zoukankan      html  css  js  c++  java
  • 「2019.7.29 考试」什么都无法舍弃的人什么也无法改变

      总的来说是比较失败的一次考试,两个半小时死刚T1,剩下不到四十分钟写T3,很仓促,爆了0。时间分配严重不均匀导致T3虽然想到了部分解法但是没有来得及实现和调试。

      大概考试过程就是先看了三道题,发现T3很简单,然后开始想,三分钟秒掉式子,大概7:22的时候就切掉了(事实证明它除了一个特判的确切掉了,而且才开考7分钟我还看了表)。然后回去看第一题,发现贡献分了两半,矩形内部和矩形之间的,矩形内部可以$O(1)$得到,矩形之间的可以$O(n^2)$算出来,但是不是严格$O(n^2)$,因为矩形之间的临接边很少,没有的时候就跳就可以了。结果写了二十分钟过不了大样例,当时绝望了,调试的时候发现矩形越多数值越小我就很纳闷,但是最终也没调出来(其实是矩形边界处理出了问题,出现了负数)。于是去做T2,基本也是秒出解(虽然不太完善但基本和正解差不多,除了合并方式上),然后十分钟敲了两颗树开始维护,只过了小样例,还是大的过不去,一直调到考试结束,于是T3愉快爆0。

      下面是题解,但是这个东西仿佛不是这次考试最重要的收获,我觉得应该是一些关于心态方面的启发,这些我会在最后说。

    T1:

      是真的暴力分情况而且没水平我实在懒得写

      贡献分两部分,

      内部贡献=$ 2(x2-x1)(y2-y1) $

      边界贡献=$ 2(边界长度)+[一端坐标不一样]+[另一端坐标不一样] $

      暴力枚举加起来即可,到没有边界的时候$break$掉即可

    T2:

      比较强的一道题,考场上想到了时间轴建树,想到了二分$size$查排名前$k$的数,想到了合并(假的线段树合并,应该是启发式合并)。

      想了很久一直没有结果,因为我的线段树合并是以不遍历全部节点为复杂度保障,但是合并了之后又无法断定哪些点是具有贡献的,这让我很难受,最后我取了暴力的方法,暴力查哪些节点是被重复计算的,贡献置0,但是会重复计算,比如说在某一个子树的时候某个时间的已经被计算过是无用的,那么接下来子树合并的过程中,他永远不可能继续有用,那么就可以不查了,但是我考场上没有想到这一点,也许这样可以挽救我死了的线段树合并思路。

      剩下的就是启发式合并了。合并什么呢?我们不合并线段树,合并操作,或许你觉得这很暴力,但是他有一定的复杂度保证$(O(nlog_2n))$。

      启发式合并其实很简单,就是把小的塞到大的里面,这样的话可以使得代价降到最低,复杂度怎么来的呢?假设我们每次合并的复杂度是$(O(n))$,而最劣的情况就是我每次拿一个和你一样大的塞你,这样我每次增大一倍,也就是会增加$(log_2n)$次,那么总的复杂度就是$O(nlog_2n)$

      复杂度是有保障的,那么怎么合并呢?考虑树上的“大”是什么意思。颓了一篇很不详细的题解就明白了。对,是重儿子。重儿子是你最大的子树,其他的子树在处理完成之后直接在线段树上打标记删除掉即可,而重儿子万万不能删除,因为你的操作要建立在重儿子的基础上操作,这样能够保证复杂度。

      我当时没有想到维护线段树的方式这么暴力。。。

      把自己的操作插入重儿子的$vector$(一般情况下重儿子操作比我身上的要多,毕竟我就一个节点)然后交换位置,再把其他轻儿子的操作插入我的$vector$,这样完成了多次启发式合并,复杂度保证是$O(nlog_2n)$。

      刚才突然想了一下,轻重划分不应当以字节点的大小作为划分依据,而应当用子节点$vector$大小,他快了$100ms$。

      而每次操作都对应线段树的一次修改或者删除。

      总复杂度就是$O(nlog_2^2n)$

      每次递归的进行这个过程,就可以完美解决这道题。

      说的比较潦草,不懂评论区。

    #include<cstdio>
    #include<cmath>
    #include<vector>
    #include<iostream>
    #include<map>
    using namespace std;
    const int maxn=1e5+5,INF=0x3f3f3f3f;
    map<int,int> mp;
    vector<int> bl[maxn],dr[maxn];
    int n,m,q,cnt,tot,x,y,a[maxn],first[maxn],ans[maxn],sz[maxn],son[maxn],t[maxn];
    struct road{
        int u,t,nxt;
    }eage[maxn<<1];
    void add(int x,int y)
    {
        eage[++tot].u=x;
        eage[tot].t=y;
        eage[tot].nxt=first[x];
        first[x]=tot;
    }
    struct SegmentTree{
        int tot,data[maxn<<2],sz[maxn<<2],f[maxn<<2];
        void FoundData(int x)
        {
            data[x]=data[x<<1]+data[x<<1|1];
            sz[x]=sz[x<<1]+sz[x<<1|1];
        }
        void LazyDown(int x)
        {
            if(!f[x]) return ;
            f[x<<1]=f[x<<1|1]=1;
            data[x<<1]=data[x<<1|1]=sz[x<<1]=sz[x<<1|1]=0;
            f[x]=0;
        }
        void Updata(int x,int l,int r,int p,int d,int num)
        {
            data[x]+=d;sz[x]+=num;
            if(l==r) return ;
            int mid=(l+r)>>1;
            LazyDown(x);
            if(p<=mid) Updata(x<<1,l,mid,p,d,num);
            else Updata(x<<1|1,mid+1,r,p,d,num);
            FoundData(x);
        }
        void Sectiondin(int x)
        {
            data[x]=sz[x]=0;f[x]=1;
        }
        int SectionQuery(int x,int l,int r,int sum)
        {
            if(sum<=0) return 0;
            if(l==r) return data[x];
            int mid=(l+r)>>1,ans=0;
            LazyDown(x);
            if(sz[x<<1]<=sum)
            {
                ans+=data[x<<1];
                ans+=SectionQuery(x<<1|1,mid+1,r,sum-sz[x<<1]);
                return ans;
            }
            else return SectionQuery(x<<1,l,mid,sum);
        }
        void init(int x)
        {
            for(int i=0;i<bl[x].size();i++)
            {
                int col=bl[x][i],r=dr[x][i];
                if(!t[col]) Updata(1,1,m,r,1,0),t[col]=r;
                else if(t[col]>r)
                {
                    Updata(1,1,m,t[col],-1,0);
                    Updata(1,1,m,r,1,0);
                    t[col]=r;
                }
                Updata(1,1,m,r,0,1);
            }
        }
        void dinit(int x)
        {
            Sectiondin(1);
            for(int i=0;i<bl[x].size();i++) t[bl[x][i]]=0;
        }
    }zt;
    void insert(int x,int y)
    {
        for(int i=0;i<bl[y].size();i++)
        {
            bl[x].push_back(bl[y][i]);
            dr[x].push_back(dr[y][i]);
        }
        bl[y].clear();dr[y].clear();
    }
    void dfs1(int x,int fa)
    {
        sz[x]=bl[x].size();
        for(int i=first[x];i;i=eage[i].nxt)
            if(eage[i].t!=fa)
            {
                dfs1(eage[i].t,x);
                sz[x]+=sz[eage[i].t];
                if(sz[son[x]]<sz[eage[i].t]) son[x]=eage[i].t;
            }
    }
    void dfs(int x,int fa)
    {
        for(int i=first[x];i;i=eage[i].nxt)
            if(eage[i].t!=fa&&eage[i].t!=son[x])
            {
                dfs(eage[i].t,x);
                zt.dinit(eage[i].t);
            }
        if(son[x]) dfs(son[x],x);
        zt.init(x);
        for(int i=first[x];i;i=eage[i].nxt)
            if(eage[i].t!=fa&&eage[i].t!=son[x])
                zt.init(eage[i].t);
    ans[x]=zt.SectionQuery(1,1,m,a[x]);
        if(son[x])
        {
            insert(son[x],x);
            swap(bl[son[x]],bl[x]);
            swap(dr[son[x]],dr[x]);
            for(int i=first[x];i;i=eage[i].nxt)
                if(eage[i].t!=fa)
                    insert(x,eage[i].t);
        }
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            if(mp[y]==0) mp[y]=++cnt,y=cnt;
            else y=mp[y];
            bl[x].push_back(y);
            dr[x].push_back(i);
        }
        sz[0]=-1;
        dfs1(1,0);
        dfs(1,0);
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d",&x);
            printf("%d
    ",ans[x]);
        }
        return 0;
    }
    ac

     

    T3:

      说实话真的很水,三分钟秒掉式子。大概说一下。

      设$dp[i][j]$为前$i$题最高难度为$j$的概率,$w[i]$为每种难度的劳累值。

      初始化:

        $dp[0][0]=1$

      转移:

        $dp[i][j]=inv_m(sum  limits_{k=0}^j dp[i-1][k]+(j-1)dp[i-1][j])$

      解释一下,我当前的最大难度是$j$的可能性有两个:

      1.我之前某些点或者达到或者没达到,但是在我这里都达到了,也就有了前面那个$sum$

      2.我之前某些点达到了而我没有达到,那就是我有$(j-1)$种情况,所以乘上$(j-1)$。

    然后就切掉了。

    下面说些心态的问题:

      我当时秒切T3觉得自己可厉害了可厉害了我心想这次稳了啊,爷要AK了啊,结果结果还是T1一调不出来心态就崩了,心想我怎么就调不出来。

      心态这个东西很微妙,你永远不知道他怎么调整或者有什么影响。我之前能做到的是考前不对这次考试报任何希望,可是在答题过程中却犯了这些禁忌,期望过高了,导致一但有什么波折就死心态。如果你是真的强三道题都全秒掉的话其实也没啥问题,但是我这种一般人做不到全秒,而且喜欢自负的觉得自己能做到全秒。虽然真的基本都正解了,可是还是能力不足没有拿到分数。

      那再立个$flag$下次要做到的是不在考前有任何期望,不再考试的时候有任何期望,心如止水。

      还有另外一个东西叫舍得。

      有舍才有得,考场上很多东西都要懂得取舍,不是文化课那两下子,直接从头做就行了的,可能丢失掉这一部分会换来更大的成绩,这时候应当不再优柔寡断,不要在侥幸的以为在过五分钟你就能调出来,事实上到考试结束你也调不出来。舍得出去才能有得到,这是毋庸置疑的,考场上就那么多时间,拿到做多得分是最重要的,而不是去作出一道你耗费了大量心血或者一眼正解的题,没有意义,这是考试不是刷题,刷题刷一天也没人管你,但考试就三个半钟头,考的出来是他,考不出来也是他了。

      但是有时候并非有舍一定会有得,可能舍弃的是一个重要的作出某道题机会。但是考场时间非常紧迫,不管对错的选择,都没有时间回头想。

      为自己的选择决定,决定了就去做,为决定负责,即使即将要为他后悔,在所不辞。

      什么都无法舍弃的人什么也无法改变。

      想起来之前看到的一句话,虽然没什么关系,但至少教会你负责任。

      

      你是个小人物,一生难得做一件大事,这个机会很宝贵,要好好珍惜。你可以偶尔发个疯,死一个人不要紧,自己死了也不要紧,可是有些事不能逃避。树要开花,人要长大。       

                                           ——江洋

     

    以上。

  • 相关阅读:
    BZOJ 1996: [Hnoi2010]chorus 合唱队
    BZOJ 2431: [HAOI2009]逆序对数列
    BZOJ1013: [JSOI2008]球形空间产生器sphere
    BZOJ 4196: [Noi2015]软件包管理器
    BZOJ 3670: [Noi2014]动物园
    NOIP 2017 提高组 day1t2 时间复杂度
    loj #6278. 数列分块入门 2
    CF285 E Positions in Permutations——“恰好->大于”的容斥和允许“随意放”的dp
    洛谷 1969 积木大赛——水题
    洛谷 1965 转圈游戏——水题
  • 原文地址:https://www.cnblogs.com/Lrefrain/p/11267557.html
Copyright © 2011-2022 走看看