总之就是 | ZROI CSP联测 Day6

「启」

虽然最终的结果是涨一点点了 rating,但实际上是前几次保灵垫出来的(

实际上这是最惨淡的一次 ZROI-CSP 测试。

除了正解,有时候会把我考场想到的一些东西扔到这里面。

缺省源使用「V5」.

「A」聚会

可以说是手速题,但是因为自己过于自信忘了看自己写的复杂度是多少痛失 60 pts.

「A」题目简述

给定一个长度为 \(n \ (n \le 5 \times 10^5)\)\(01\) 序列,求所有位置到其最近的 \(1\) 的距离之和。

「A」思路简述

首先是我场上完全没有意识到自己写的是 \(O(n^2)\) 的惨淡思路……

「A」40 pts

我一开题,本着手速题不能多吃罚时的理念,随便敲了一个就交上去没再管,而且后来拍了拍也是对的,就没管。(然而对拍的数据远不及 \(5 \times 10^5\)

大体的思路就是对于每一个 \(0\) 分别去左右找离它最近的 \(1\),复杂度是 \(O(n^2).\)

「A」100 pts

正解显然不是 \(O(n^2)\) 这种连 60 pts 都没有的垃圾算法。

实际上最一开始做的时候也想到这个了,但是阴差阳错就没写这个(

思路很简单,就算分别从左往右和从右往左求出 \(l_i\)\(r_i\),分别代表左右离 \(i\) 最近的 \(1\) 的距离。

「A」Code

依次是 \(40\) 和正解。

「A」40 Code

template<typename J>
I J Hmin(const J &x,const J &y) {Heriko x<y?x:y;}

CI MXX(5e5+1);

int T,n;

char s[MXX];

S main()
{
    fr(T);

    for(int t(1);t<=T;++t)
    {
        fr(n);scanf("%s",s+1);LL ans(0);
        
        for(int i(1);i<=n;++i)
            if(s[i]=='0')
            {
                int step(0),temp(0x3f3f3f3f);

                while(i-step>=1)
                {
                    ++step;

                    if(s[i-step]=='1')
                    {
                        temp=step;break;
                    }
                }

                step=0;

                while(i+step<=n)
                {
                    ++step;

                    if(s[i+step]=='1')
                    {
                        temp=Hmin(step,temp);break;
                    }
                }

                ans+=temp;
            }

        printf("Case #%d: %lld\n",t,ans);
    }

    Heriko Deltana;
}

「A」AC Code

template<typename J>
I J Hmin(const J &x,const J &y) {Heriko x<y?x:y;}

CI MXX(5e5+1),INF(0x3f3f3f3f);

int T,n,l[MXX],r[MXX];

char s[MXX];

S main()
{
    Files();
    fr(T);

    for(int t(1);t<=T;++t)
    {
        fr(n);scanf("%s",s+1);
        LL ans(0);mst(l,0x3f);mst(r,0x3f);

        int lstone(-1);
        
        for(int i(1);i<=n;++i)
            if(s[i]=='1') lstone=i;
            else
            {
                if(lstone==-1) l[i]=INF;
                else l[i]=i-lstone;
            }

        lstone=-1;

        for(int i(n);i;--i)
            if(s[i]=='1') lstone=i;
            else
            {
                if(lstone==-1) r[i]=INF;
                else r[i]=lstone-i;
            }

        for(int i(1);i<=n;++i)
            if(s[i]=='0')
                ans+=Hmin(l[i],r[i]);

        printf("Case #%d: %lld\n",t,ans);
    }

    Heriko Deltana;
}

「B」跳房子

构造题,为什么最近总是考构造题(

想了半天找不到构造规律,最后交了个随机化跑路了……

「B」题目简述

现有 \(n \ (n \le 1000)\) 个格子和 \(3\) 个人,每个格子 \(i\) 有其权值 \(x_i \ (x_i \le 10^{18})\),保证序列 \(x\) 是严格递增的。

每一对格子 \((a,b)\) 必须三个人里的一个人。

现在每个人开始跳房子,一个人可以从 \(i\) 跳到 \(j\),当且仅当:

  • \(i < j;\)

  • \((i,j)\) 属于这个人;

  • \(x_i | x_j.\)

现在要对每一对格子 \((a,b)\) 进行分配,使得:不管从哪个位置出发,都不会有一个人连续跳三次以上。

「B」思路简述

说实话看了题解之后才发现这个构造如此巧妙(

我们设 \(f(x)\) 表示 \(x\) 在二进制表示下为 \(1\) 的最高位。

然后把除以 \(4\) 相同的一对位置分给第一个人,除以 \(16\) 相同的一对位置分给第二个人,剩下的给第三个人。

因为对于每一对 \((a,b)\),有 \(a|b , a < b \Rightarrow a \le 2b\),所以对于每个分配,组内都不会超过四个。

对于求 \(f(x)\),我们只需要不断地将 \(x\) 右移一位直到 \(x\) 只剩下一位即可。

「B」Code

CI MXX(1001);

int n;

LL a[MXX],f[MXX];

I LL FstOne(LL x)
{
    LL res(0);

    while(1)
    {
        x>>=1;++res;

        if(x==1) break;
        else if(!x) {--res;break;}
    }

    Heriko res;
}

S main()
{
    fr(n);

    for(int i(1);i<=n;++i) fr(a[i]);
    
    for(int i(1);i<=n;++i) f[i]=FstOne(a[i]);

    for(int i(2);i<=n;puts(""),++i)
        for(int j(1);j<i;++j)
            if((f[i]/4)==(f[j]/4)) fw(1,0);
            else if((f[i]/16)==(f[j]/16)) fw(2,0);
            else fw(3,0);

    Heriko Deltana;
}

「C」人结

谢谢已经结在一起了。

「C」题目简述

圆上有 \(n\) 个点,按照顺时针标号,每个点与两个点相连,要求通过移动点在圆上的位置,使得最终的边没有交叉的一个环。

image.png

「C」思路简述

当且仅当整张图不连通的时候无解,所以我们先找个环,找不到乆无解。

然后断环为链之后做一遍 LIS,做一遍 LCS,这里是翻转了数组做了两遍 LIS.

「C」Code

template<typename J>
I J Hmax(const J &x,const J &y) {Heriko x>y?x:y;}

CI MXX(501);

int n,a[MXX];

struct Node
{
    int nex,to;
}

r[MXX<<1];int cnt,head[MXX];

I void Add(int x,int y) {r[++cnt]=(Node){head[x],y};head[x]=cnt;}

bool vis[MXX];

int tot,ans;

void GetRing(int x)
{   
    vis[x]=1;a[++tot]=x;

    for(int i(head[x]);i;i=r[i].nex)
        if(!vis[r[i].to])
            GetRing(r[i].to);
}

int f[MXX],q[MXX],tl;

I void LIS()
{
    for(int i(1);i<=n;++i) a[i+n]=a[i];

    for(int i(1);i<=n;++i)
    {
        mst(f,0),mst(q,0);tl=0;

        for(int j(i);j<=i+n-1;++j)
        {
            if(a[j]>q[tl]) q[++tl]=a[j];
            else q[lower_bound(q+1,q+tl+1,a[j])-q]=a[j];

            f[j-i+1]=tl;
        }

        ans=Hmax(ans,f[n]);
    }
}

S main()
{
    Files();

    while(1)
    {
        fr(n);
        
        if(!n) break;

        mst(vis,0),mst(head,0),mst(a,0);
        cnt=tot=ans=0;

        for(int i(1);i<=n;++i) {int x,y;fr(x),fr(y),Add(i,x),Add(i,y);}

        GetRing(1);

        if(tot!=n) {puts("Not solvable.");continue;}
        else puts("Knot solvable.");

        LIS();reverse(a+2,a+1+n);
        LIS();fw(n-ans,1);
    }

    Heriko Deltana;
}

「D」辣椒

我剪不开辣椒,我是垃圾。

「D」题目简述

\(n\) 个辣椒,用 \(n−1\) 根绳子连接,所以每两个辣椒都可以通过一些绳子连接在一起。也就是说,它们形成一棵树。

现在要准备今天的三顿饭。为此,他将剪断两根绳子以得到三个较小的辣椒串,每餐一个。

当然,每一餐饭太辣是不好的,所以要选择尽量减少最大辣度辣椒串和最小辣椒串之间的大小差异,注意辣椒串的辣度就是辣椒串包含辣椒的个数。你需要寻求这个最小差异是多少。

「D」思路简述

\(O(n^2)\) 做法即为枚举两个点 \(x,y\),然后把这两个点连向父亲的边断掉,设 \(sz(x)\) 为以 \(x\) 为根的子树大小,则剩下的三部分大小有以下的情况:

  • \(y\)\(x\) 的祖先,则三部分大小分别为:\(sz(x),sz(y)-sz(x),n-sz(y);\)

  • \(y\)\(x\) 没有祖孙关系,那么为:\(sz(x),sz(y),n-sz(x)-sz(y).\)

然后维护从根到 \(x\) 上的路径的点的点集,从中找到一个点 \(z\) 使得 \(|sz(y) - \dfrac{n+sz(z)}{2}|\),用 set 维护,用 lower_bound() 查找,在深度变大的时候加入新点。同时维护一个已经处理过但是非 \(x\) 祖先的点集,在其中找到一点使得 \(|sz(y)-\dfrac{n-sz(z)}{2}|\),维护方式相同,当一个点被删除的时候,将其从直系集中取出,加入旁系集,总的时间复杂度为 \(O(n \log n).\)

「D」Code

template<typename J>
I J Hmax(const J &x,const J &y) {Heriko x>y?x:y;}

template<typename J>
I J Hmin(const J &x,const J &y) {Heriko x<y?x:y;}

CI MXX(5e5+1),INF(0x3f3f3f3f);

int n,ans(INF);

struct Node
{
    int nex,to;
}

r[MXX];int cnt,head[MXX];

I void Add(CI &x,CI &y) 
{
    r[++cnt]=(Node){head[x],y};head[x]=cnt;
    r[++cnt]=(Node){head[y],x};head[y]=cnt;
}

I int Dlt(CI &x,CI &y,CI &z) {Heriko Hmax(Hmax(x,y),z)-Hmin(Hmin(x,y),z);}

int sz[MXX];

void DFS1(int x,int fa)
{
    sz[x]=1;

    for(int i(head[x]);i;i=r[i].nex)
    {
        int y(r[i].to);

        if(y==fa) continue;

        DFS1(y,x);sz[x]+=sz[y];
    }
}

set<int> s1,s2,cs1,cs2;

void DFS2(int x,int fa)
{
    if(s1.size()) 
    {
        int pos(*s1.lower_bound((n+sz[x])>>1));
        ans=Hmin(ans,Dlt(n-pos,sz[x],pos-sz[x]));
    }

    if(s2.size()) 
    {
        int pos(*s2.lower_bound((n-sz[x])>>1));
        ans=Hmin(ans,Dlt(sz[x],pos,n-pos-sz[x]));
    }

    if(cs1.size()) 
    {
        int pos(*cs1.lower_bound(-((n+sz[x])>>1)));pos=-pos;
        ans=Hmin(ans,Dlt(n-pos,sz[x],pos-sz[x]));
    }

    if(cs2.size()) 
    {
        int pos(*cs2.lower_bound(-((n-sz[x])>>1)));pos=-pos;
        ans=Hmin(ans,Dlt(sz[x],pos,n-pos-sz[x]));
    }

    s1.insert(sz[x]),cs1.insert(-sz[x]);

    for(int i(head[x]);i;i=r[i].nex)
        if(r[i].to!=fa)
            DFS2(r[i].to,x);

    s1.erase(sz[x]),cs1.erase(-sz[x]);
    s2.insert(sz[x]),cs2.insert(-sz[x]);
}

S main()
{
    Files();
    fr(n);

    for(int i(1),x,y;i<n;++i) fr(x),fr(y),Add(x,y);

    DFS1(1,0);DFS2(1,0);fw(ans,1);

    Heriko Deltana;
}

「末」

6 Days Left.

posted @ 2021-10-17 19:50  HerikoDeltana  阅读(53)  评论(0编辑  收藏  举报