• 模测8


    07,25.

    这次考试题忽然水辽。。

    然而我也水辽///

    这是预估期望/能力范围分数。

    这是实际分数·「·」·「·」·「·」

    曾经有一份巨水的T2,摆在我面前,

    但是我没有好好珍惜?_?

    如果给我一次机会,

    我会把考后五分钟加上的不到30个字符码上去。

    说总结:

    T0:水题还是打的慢,不太熟,分析题意应该多想,整体思路应该多想,但是打代码应该速度。熟练度问题。以及思考速度。

    T340分其实极限了,超出能力范围的东西还是先放一放。模拟考试就是模拟noip,总分更重要。

    当时太想A掉T3了,而且想出了线段树优化的思路(当时没想清楚,以为线段树都是nlogn的,但实际上是(1/2n^2logn+1/2nlogn)的......还不如n^2DP

    制杖题目背景还提到平衡树和数据结构,然后我想出DP后就一直想平衡树或其他数据结构优化。

    但实际上和数据结构一点关系都没有。。。

    对于超出能力范围的题目,还是先保证拿到水题分数,再去刚。而且水题要多分析题意,但是做快点。

    稳在考前,水在考中,刚在考后。

    T1 kmp模板,但是hash好像好打,但是我忘了,但是别人好像都只会hash不会kmp,所以只有我觉得kmp比hash简单???

    T2 题意理解:1、割点。2、能分开1,n。即删去当前点后能将1,n分为两个联通快。否则不是必经的,是无效的。

    之所以觉得简单是没有思考全面。虽然考试时想到了要分开1和n,但是并没有想全。没有写出好的样例。

    有的分支路径能到达1和n,但是并非必经。

    这题虽然不用再建一棵圆方树,但是此操作确实不熟,要看看。

    但是建树的同学数组要开8倍,因为数组没开够被卡到80,可见建树不够优秀。

    垃圾比大神吴孟周建树:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #define db(x) cerr<<#x<<"="<<x<<endl
    using namespace std;
    const int N=200010;
    inline int read()
    {
        int x=0; char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch))
        {
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x;
    }
    int n,m,dcc;
    int tot,head[N*3],nxt[N*8],to[N*8];
    int low[N],dfn[N],num,stack[N],top;
    int fa[3*N],bl[N];
    vector<int> ve[N*2];
    inline void add(int a,int b)
    {
        to[++tot]=b;
        nxt[tot]=head[a];
        head[a]=tot;
    }
    bool cut[N];
    void tarjan(int x,int from)
    {
        low[x]=dfn[x]=++num;
        stack[++top]=x;
        int flag=0;
        for(int i=head[x];i;i=nxt[i])
        {
            if(!dfn[to[i]])
            {
                tarjan(to[i],i);
                low[x]=min(low[x],low[to[i]]);
                if(low[to[i]]>=dfn[x])
                {
                    flag++;
                    if(flag>1||x!=1) cut[x]=1;
                    ++dcc;
                    int y;
                    do{
                        y=stack[top--];
                        bl[y]=dcc;
                        ve[dcc].push_back(y);
                    }while(y!=to[i]);
                    bl[x]=dcc;
                    ve[dcc].push_back(x);
                }
            }
            else if(i!=(from^1)) low[x]=min(low[x],dfn[to[i]]);
        }
    }
    void dfs1(int x)
    {
        for(int i=head[x];i;i=nxt[i])
        {
            if(to[i]==fa[x]) continue;
            fa[to[i]]=x;
            dfs1(to[i]);
        }
    }
    bool v[N*3];
    int main()
    {
        //有自环有重边
        //有自环有重边
        //有自环有重边
        int T=read();
        while(T--)
        {
            for(int i=1;i<=dcc;++i) ve[i].clear();
            tot=1; num=0; top=0; dcc=0;
            memset(dfn,0,sizeof dfn);
            memset(head,0,sizeof head);
            memset(cut,0,sizeof cut);
            memset(v,0,sizeof v);
            memset(fa,0,sizeof fa);
            memset(bl,0,sizeof bl);
            n=read(); m=read();
            for(int i=1,a,b;i<=m;++i)
            {
                a=read(); b=read();
                add(a,b); add(b,a);
            }
            tarjan(1,0);
            memset(head,0,sizeof head); tot=1;
            for(int i=1;i<=dcc;++i) 
                for(unsigned j=0;j<ve[i].size();++j)
                    if(cut[ve[i][j]])
                        add(i,ve[i][j]+dcc),add(ve[i][j]+dcc,i);
            dfs1(cut[1]?dcc+1:bl[1]);
            int x=cut[n]?n+dcc:bl[n];
            while(fa[x]) v[x]=1,x=fa[x];
            int cnt=0;
            for(int i=2;i<n;++i) if(v[i+dcc]) ++cnt;
            printf("%d
    ",cnt);
            for(int i=2;i<n;++i) if(v[i+dcc]) printf("%d ",i);
            puts("");
        }
        return 0;
    }
    View Code

    考前觉得tarjan不太熟,本来想看看,但是觉得这么新的知识点不会考,成功把自己hack

    T3 要卡常。。。没必要的数组清零memset卡掉我5分。本来是40分。。。

    或者LL数组改成int。。因为只能过小点,用不着LL,而且跑的慢要卡一卡,当然要用int。卡卡出奇迹。

    n^2DP理论40,但也有50的不知道怎么卡的,要去看看。

    山大附的郭神打的三分,本来我也看出了单谷的性质,是三分,但是没学过。。。

    线段树优(tui)化思路:

    线段树区间修改标记,区间加,区间最小值。

    维护:节点存某点的值

    sl,sr:前后缀1的个数

    p:sl和sr的修改标记

    f,g:DP数组中的单点值。f=f(i),g=g(i+1)。

    断点c向右移动,遇到1时,f和g除断点处外是不会变的。而断点处u与上一个1的位置有关。预处理后可以O(1)求。线段树中logn改。

    遇到0,整个加减(断点特殊):f-=sl,g+=sr;但是每个点都要改,相当于重新建树,单次nlogn.

    极限数据总复杂度1/2n^2logn+1/2nlogn;

    min(B,R)<=30,稳过。但是自己能想出新的思路,虽然退化了,但还是值得成就感。

    正解:在枚举断点(n)和分界点(n)的n^2 DP基础上:

    手模加感性思考可以发现断点向右移动时,分界点单调右移。(在拆环成2n的链基础上)(同为顺时针)

    则枚举断点,分界点可以用while找。(分界点在"0"个数的中位(注意奇偶)证明见skyh和yxs这两尊机油大神)

    在已知断点和分界点后,w=f+g可以O(1)求。用前缀和预处理,小容斥减一下,减去多余部分即可。

    p为分界点。

    LL w=f[p]-f[i]-(LL)(i-sl[i])*(sl[p]-sl[i])+
                    g[p+1]-g[i+n+1]-(LL)(hx-sr[i+n+1]-(i+n))*(sr[p+1]-sr[i+n+1]);

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define F(i,a,b) for(rg int i=a;i<=b;++i)
    #define il inline 
    #define LL long long
    #define cst const
    #define rg register
    #define pf(a) printf("%3d ",a)
    #define PF(a) printf("%3lld ",a)
    #define phn printf("
    ")
    using namespace std;
    int read();
    //-2,n,1
    #define NX 1000010
    #define min(a,b) (a<b?a:b)
    #define me(a) memset(a,0,sizeof(a))
    char zfc[NX];
    int a[NX<<1],sl[NX<<1],sr[NX<<1],sum0[NX<<1],tot0;
    LL f[NX<<1],g[NX<<1];
    int n;
    const LL MAXN=0x7ffffffffff;
    int main(){
        int T=read();
        while(T--){
            tot0=0;
            scanf("%s",zfc+1);
            n=strlen(zfc+1);
            F(i,1,n){
                if(zfc[i]=='B')a[i]=1,a[i+n]=1;
                else a[i]=0,a[i+n]=0,++tot0;
            }
            rg int hx=(n<<1);
            F(i,1,(n<<1)){
                f[i]=f[i-1]+1ll*a[i]*(i-1-sl[i-1]);
                sl[i]=sl[i-1]+a[i];
                sum0[i]=sum0[i-1]+(a[i]==0?1:0);
            }
            for( int i=(n<<1);i>=1;--i){
                g[i]=g[i+1]+1ll*a[i]*(hx-i-sr[i+1]);
                sr[i]=sr[i+1]+a[i];
            }
    //        F(i,1,n<<1)pf(i);phn;
    //        F(i,1,n<<1)PF(f[i]);phn;
    //        F(i,1,n<<1)PF(g[i]);phn;
    //        F(i,1,n<<1)pf(sl[i]);phn;
    //        F(i,1,n<<1)pf(sr[i]);phn;
            //LL w=f[9]-f[1]-(LL)(1-sl[1])*(sl[9]-sl[1]);
            //PF(w);
            LL ans=MAXN;rg int p=1;
            const int goal=(tot0&1)?(tot0/2+1):(tot0/2);
            for( int i=1;i<=n;++i){
                while(sum0[p]-sum0[i]<goal){
                    ++p; //if(p>n*2)p=1;
                }
                LL w=f[p]-f[i]-(LL)(i-sl[i])*(sl[p]-sl[i])+
                    g[p+1]-g[i+n+1]-(LL)(hx-sr[i+n+1]-(i+n))*(sr[p+1]-sr[i+n+1]);
        //        PF(w);
                ans=min(ans,w);
            }
        //    phn;
            printf("%lld
    ",ans);
        }
        return 0;
    }
    il int read(){
        rg int s=0,f=0;rg char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
        while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch^48);ch=getchar();}
        return f?-s:s;
    }    
    /*
    g++ 1.cpp -g
    ./a.out
    2
    BBRBBRBBBRRR
    RRRBBBRBBRBB
    */
    //多测,对拍??
    View Code

    另:郭神T3三分可做:

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<queue>
    #define ll long long
    using namespace std;
    const int MAXN=1000005;
    int T,n,pos;
    ll suml[MAXN*2],sumr[MAXN*2],ans=0x3f3f3f3f3f3f3f3f;
    int bcntl[MAXN*2],bcntr[MAXN*2],rcnt[MAXN*2];
    char s[MAXN*2];
    inline void R() {
        char c=getchar();
        while(c!='B'&&c!='R') c=getchar();
        while(c=='B'||c=='R') s[++n]=c,c=getchar();
    }
    ll calcl(int l,int r) {
        return suml[r]-suml[l-1]-(ll)bcntl[l-1]*(rcnt[r]-rcnt[l-1]);
    }
    ll calcr(int l,int r) {
        return sumr[l]-sumr[r+1]-(ll)bcntr[r+1]*(rcnt[r]-rcnt[l-1]);
    }
    ll js(int l,int p,int r) {
        return calcl(l,p)+calcr(p+1,r);
    }
    ll find(int l,int r) {
        while(pos<=2*n)
            if(js(l,pos+1,r)<=js(l,pos,r)) pos++;
            else break;
        return js(l,pos,r);
    }
    int main() {
        scanf("%d",&T);
        while(T--) {
            R();
            for(int i=1;i<=n;++i) s[n+i]=s[i];
            suml[0]=0; bcntl[0]=rcnt[0]=0;
            
            for(int i=1;i<=n*2;++i) {
                suml[i]=suml[i-1];
                bcntl[i]=bcntl[i-1]; rcnt[i]=rcnt[i-1];
                if(s[i]=='B') ++bcntl[i];
                else ++rcnt[i];
                if(s[i]=='R') suml[i]+=bcntl[i];
            }
            sumr[2*n+1]=0; bcntr[2*n+1]=0;
            for(int i=2*n;i>=1;i--) {
                sumr[i]=sumr[i+1];
                bcntr[i]=bcntr[i+1];
                if(s[i]=='B') ++bcntr[i];
                else sumr[i]+=bcntr[i];
            }
            pos=1;
            for(int i=1;i<=n;i++)
                ans=min(ans,find(i,i+n-1));
            printf("%lld
    ",ans);
            n=0;ans=0x3f3f3f3f3f3f3f3f;
        }
        return 0;
    }
    View Code

     观察规律找性质。

    (这wmz和zdy真是稳如gou)

    所以一定要把该拿的分都拿到,那就是top3

    Informatik verbindet dich und mich. 信息将你我连结。
  • 相关阅读:
    关于在组件GIS开发中使用Python的一点补充说明
    shell环境变量以及set,env,export的区别
    快速配置 Samba 将 Linux 目录映射为 Windows 驱动器
    Expect 教程中文版
    rpm 包管理
    .bash_profile和.bashrc的什么区别
    grep 零宽断言
    自动化测试
    dialog shell下的gui设计 代替繁杂libncurses编程
    x11 gtk qt gnome kde 之间的区别和联系
  • 原文地址:https://www.cnblogs.com/seamtn/p/11248207.html
Copyright © 2020-2023  润新知