• 0922CSP-S模拟测试赛后总结


    连发三篇爆炸实录我的心态竟然还这么好……

    昨天题目的D2。稍难。

    这也不是我连续拿倒数第一的理由。

    T1不会。赛时硬写了一个30分的三次方暴力。还有一个地方写挂了。如果不是数据足够水我就爆零了。

    也就是说我的11分subtask1还是捡来的。

    最难过的是T2。T2写了乱搞(正解之一??)。然而并没有调出来。

    二维莫队。我写的很顺。没什么细节错误。然而,

    我是在最后20分钟才开始打的。也就是说我最一开始并没有打二维莫队。

    一方面是觉得这东西复杂度应该不对。另一方面,我不会离散化。

    对。我不会离散化。

    之前学离散化的时候就不是很理解。记得还是OJ能发帖子的时期。我还在OJ里发了个帖子问了一下。

    当时还不是很熟的wba大神还给回了。然而依旧不理解。就这么放过去了。

    后来也遇到了几道需要离散化的题。全都是靠着利哥坐我旁边指导着我那一句话该怎么写才过掉。

    也就是说,我从来从来没有独立写过离散化。

    对。就这短短的几行,几句话,我从来没有自己,认认真真的写过。

    我也从来没有想到过,有一天我会死在离散化上。

    然而这就是发生了。突如其来,刻骨铭心。

    以小见大。我给自己挖的坑到底有多少,谁也不知道。

    基础不牢,地动山摇。

    大神绝对不仅仅是会几个强大的算法,会复杂的数学。

    基础同样重要。从今天起要填坑了。庆幸吧,这不是CSP-S2019的赛场。

    但如果这还没有给我敲响警钟的话,这就是我在CSP-S2019的下场。

    最后强行yy了离散化上去。以为自己打的是对的。然而并不对。

    lower_bound的一个参数写错了。样例死活过不去。

    赛后整整20分钟,我才发现了这个错误。A掉了。

    然而,假如这是CSPS的赛题。我又能如何呢。填坑,势在必行了。


    又是好久没有写题解了。每天被大佬们拖着走吊着打的感觉……emmmp。

    昨天某考试报名于是没有考试,才有时间来写一波题解。顺便祭奠一下垫底记。

    T1施工(单调栈优化dp)

    我可以管这个东西叫填坑dp么/大雾

    我们设$f_i$为转移到i位置,且第i个位置高度不变的答案。

    关于$f_i$的转移我们可以推出性质:

    对于一个位置$i$和它前面一个位置$j$,一定要将它们之间填平才能继续转移。

    (填平是指填成平地而非一定要和$i$、$j$平齐,原因待会儿解释)

    我们假设$f_i$从$f_j$转移而来且$i$、$j$之间填平后高度为t。

    则显然$i$、$j$之间对答案的贡献为:

    $sumlimits_{k=j+1}^{i-1}(t-h_k)^2+c(h_j+h_i-2t)$

    (式子解释:$sum(t-h_k)^2$是填坑的花费,填平后的不美观度只有两头的贡献。所以为$c(h_j+h_i-2t)$)

    于是中间的高度可以由二次函数对称轴公式计算。最后计算式子的最小值。

    一次项系数中的$sum h_k$和常数项里的$sum h_k^2$直接前缀和维护一下就可以$O(1)$查询了。

    考虑那些点可以用来转移$f_i$。

    一个点j可以转移$f_i$当且仅当i与j之间的所有建筑高度都要小于等于$h_i$和$h_j$,并且i和j还不能挨着(否则中间没有坑)。

    因此考虑单调栈维护转移点。

    由于我是顺序扫每一个建筑,因此当扫到i的时候,栈顶一定与i相邻。

    所以用$top-1$作为转移点转移i点。

    至于转移到什么时候为止,当我扫到单调栈中某一个位置的高度已经比我要高了,那么我显然不能再跨过这个建筑与下一个建筑进行转移。也就是说不满足上述的条件停止就行了。

    一些细节需要特殊注意。

    然后解释一下上面的某个性质:假如我i、j之间并不填平,而是填成这个鬼样子:

    那么我中间填的贡献一定在i-1的时候被计算过了。

    所以只有填平才能不重不漏地更新。

    T2蔬菜(四维偏序、莫队压正解

    正解CDQ套CDQ??树状数组套CDQ??我才不要打CDQ(其实是不会打吧……)。莫队好优秀的。

    离散化一下简单莫队就好了。因为是二维的,所以四个while循环变成了八个。

    我打的是最最最暴力的一种(或许),询问排序都没分块……大佬们都用奇偶性排序……

    然后就变成了最慢的AC了……统计也是最暴力的统计。但实测可A 23333。

    T3联盟(大力dfs、错解AC

    我可以十分负责任得跟你讲:打完这道题,我看到dfs就想吐……

    我大概写了6个dfs……调了一整天……加上调试语句代码破5.0k……

    好吧我承认这是我码力太弱了。旁边大神4个dfs就解决了。

    我不想回忆过程……扔个代码就是了。

    (另外,这是错解……只能处理树上只有一个直径的情况??或者是说另外几条直径对答案没有影响。

    大概就是说ans2要输出的那几条边在这几条直径上都是重合的……正解看脸哥的。)

    #include<bits/stdc++.h>
    #define rint register int
    #define read(A) A=init()
    #define N 300005
    using namespace std;
    inline int init()
    {
        int a=0,b=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')b=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){a=(a<<3)+(a<<1)+ch-'0';ch=getchar();}
        return a*b;
    }
    int n,v[N<<1],id[N<<1],nxt[N<<1],first[N],tot=1;
    int len[2][N],lenth,len_rot,du[N],st,en,line[N],cnt,fr[N],to[N];
    int ans1=0x7fffffff,ans2_sum,ans2[N],ans3[4],len_to[2][N],oo[2];
    bool in_line[N],vis[2],ky[N];
    inline void add(int uu,int vv,int line_id)
    {
        v[++tot]=vv,id[tot]=line_id,
        nxt[tot]=first[uu],first[uu]=tot;
    }
    inline void dfs_Getlenth(int x,int fa)//true
    {
        for(rint i=first[x];i;i=nxt[i])
        {
            int y=v[i];if(y==fa)continue;
            dfs_Getlenth(y,x);len[1][x]=max(len[1][x],len[0][y]+1);
            if(len[1][x]>len[0][x])swap(len[0][x],len[1][x]);
        }
        if(len[0][x]+len[1][x]>lenth)
            lenth=len[0][x]+len[1][x],len_rot=x;
        return ;
    }
    inline void dfs_Getpoint(int x,int fa)//true
    {
        in_line[x]=1;
        if(du[x]==1){if(!st)st=x;else en=x;}
        for(rint i=first[x];i;i=nxt[i])
        {
            int y=v[i];if(y==fa)continue;
            if(len[0][y]==len[0][x]-1)
            {
    //            cout<<x<<"->"<<y<<endl;
                dfs_Getpoint(y,x);
                break;
            }
        }
        return ;
    }
    inline void dfs_Getline(int x,int fa)//true
    {
        for(rint i=first[x];i;i=nxt[i])
        {
            int y=v[i];
    //        if(fr[id[i]]==3)cout<<"the point:"<<y<<' '<<in_line[y]<<endl;
            if(y==fa||(in_line[y]==0))continue;
    //        cout<<"line: "<<id[i]<<" become true;"<<endl;
    //        cout<<x<<"->"<<y<<endl;
            line[++cnt]=id[i];ky[id[i]]=1,ky[id[i^1]]=1;
            dfs_Getline(y,x);break;
        }
        return ;
    }
    inline void dfs_Getlen(int ID,int x,int fa,int res)//true
    {
        len_to[ID][x]=max(res,len_to[ID][x]);
        int lin=0;
        for(rint i=first[x];i;i=nxt[i])
        {
            int y=v[i];if(y==fa)continue;
            if(ky[id[i]]){lin=i;continue;}
            dfs_Getlen(ID,y,x,res+1);
            len_to[ID][x]=max(len_to[ID][x],len_to[ID][y]);
        }
        len_to[ID][v[lin]]=len_to[ID][x];
        if(lin)dfs_Getlen(ID,v[lin],x,res+1);
        return ;
    }
    inline int dfs_Getans(int ID,int drie,int x,int fa)
    {
        int lin=0;
    //    cout<<"    run to the "<<x<<" point;"<<endl;
        for(rint i=first[x];i;i=nxt[i])
        {
            if(!ky[id[i]])continue;
            if(id[i]==drie)break;
            int y=v[i];if(y==fa)continue;
            lin=max(lin,dfs_Getans(ID,drie,y,x));
        }
        return max(len_to[ID][x],lin);
    }
    inline int dfs_Getans_3(int ID,int x,int fa,int res)
    {
    //    cout<<ID<<' '<<x<<' '<<fa<<' '<<res<<endl;
        if(res==((oo[ID]+1)/2))return x;
        for(rint i=first[x];i;i=nxt[i])
        {
            if(!ky[id[i]])continue;
            if(v[i]==fa)continue;
            return dfs_Getans_3(ID,v[i],x,res+1);
        }
    }
    int main()
    {
    //    freopen("dt.in","r",stdin);
    //    freopen("my.out","w",stdout);
        read(n);
        for(rint i=1,Angel,Scott;i<n;++i)
        {
            read(Angel),read(Scott),du[Angel]++,du[Scott]++,
            add(Angel,Scott,i),add(Scott,Angel,i);
            fr[i]=Angel,to[i]=Scott;
        }
        dfs_Getlenth(1,0);
    //    cout<<"lenth:"<<lenth<<endl;
    //    cout<<"len_rot:"<<len_rot<<endl;
        for(rint i=first[len_rot];i;i=nxt[i])
        {
            in_line[len_rot]=1;
            if(du[len_rot]==1)st=len_rot;
            if(vis[0]&&vis[1])break;int y=v[i];
            if((!vis[0])&&len[0][y]==len[0][len_rot]-1)
            {
    //            cout<<"the first:"<<len_rot<<"->"<<y<<endl;
                dfs_Getpoint(y,len_rot);vis[0]=1;
            }
            else if((!vis[1])&&len[0][y]==len[1][len_rot]-1)
            {
    //            cout<<"the second:"<<len_rot<<"->"<<y<<endl;
                dfs_Getpoint(y,len_rot);vis[1]=1;
            }
        }
    //    cout<<"st:"<<st<<",en:"<<en<<endl;
    //    for(rint i=1;i<=n;++i)if(in_line[i])cout<<i<<' ';cout<<endl;
        dfs_Getline(st,0);
    //    cout<<"the key lines:"<<endl;for(rint i=1;i<=cnt;++i)cout<<line[i]<<' '<<fr[line[i]]<<' '<<to[line[i]]<<endl;
        dfs_Getlen(0,st,0,0);
        dfs_Getlen(1,en,0,0);
    //    cout<<"following are debug of the dfs_Getlen:"<<endl;
    //    cout<<"  to st:";for(rint i=1;i<=n;++i)cout<<len_to[0][i]<<' ';cout<<endl;
    //    cout<<"  to en:";for(rint i=1;i<=n;++i)cout<<len_to[1][i]<<' ';cout<<endl;
        for(rint i=1;i<=cnt;++i)
        {
            int lin=0;
    //        cout<<"-------------------------"<<endl;
    //        cout<<"cutting the "<<line[i]<<endl;
    //        cout<<"  checking the Left"<<endl;
            int Left=min(len_to[0][to[line[i]]],len_to[0][fr[line[i]]]);//dfs_Getans(0,line[i],st,0);
    //        cout<<"  checking the Right"<<endl;
            int Right=min(len_to[1][to[line[i]]],len_to[1][fr[line[i]]]);//dfs_Getans(1,line[i],en,0);
    //        cout<<"cut the "<<i<<",the Left is "<<Left<<",the Right is "<<Right<<endl;
            lin=max((int)(ceil((double)Left/2)+ceil((double)Right/2))+1,max(Left,Right));
            if(lin<ans1)
            {
                ans1=lin,ans2_sum=1,ans2[1]=line[i];
                ans3[0]=fr[line[i]],ans3[1]=to[line[i]],oo[0]=Left,oo[1]=Right;
            }
            else if(lin==ans1)ans2[++ans2_sum]=line[i];
        }
    //    cout<<"oo"<<oo[0]<<' '<<oo[1]<<endl;
        ans3[2]=dfs_Getans_3(0,st,0,0);
        ans3[3]=dfs_Getans_3(1,en,0,0);
        printf("%d
    %d",ans1,ans2_sum);
        sort(ans2+1,ans2+ans2_sum+1);
        for(rint i=1;i<=ans2_sum;++i)printf(" %d",ans2[i]);puts("");
        printf("%d %d %d %d
    ",ans3[0],ans3[1],ans3[2],ans3[3]);
        return 0;
    }
    /*
    4
    1 2
    2 3
    3 4
    
    7
    1 2
    2 4
    1 3
    3 5
    3 6
    6 7
    
    8
    4 2
    5 2
    2 1
    1 3
    3 6
    6 7
    7 8
    
    */
    View Code
  • 相关阅读:
    空悬指针、野指针、内存泄漏、内存溢出
    自定义消息的操作方法ON_MESSAGE(..)
    为什么static成员变量一定要在类外初始化?
    Ubuntu 系统目录结构
    Beyond Compare 4 30天评估期结束的解决办法
    C++ string 字符串 结尾 标志
    C语言——枚举类型用法
    结构体struct-联合体union-枚举enum
    网卡bood
    kvm 安装
  • 原文地址:https://www.cnblogs.com/xingmi-weiyouni/p/11569105.html
Copyright © 2020-2023  润新知