总之就是 | ZROI NOIP联测 Day4

「0.0」序言

目前我还不会 T3(因为大概涉及一些多项式卷积的知识,然而我不会)

因为懒的造了所以就用原题目名了。

「1.0」签到题

其实最少有 \(40\) pts 来着,但没交上。

之所以正解挂成 \(40\) 是因为 \(998244353\) 写成了 \(99824353\)

「1.1」题目简述

你的左手可以输入 AB,右手可以输入 BC,每次换手的代价为 \(1\),现在需要让你用左右手交替的方法输出由 A,B,C 组成的字符串 \(T\) 的每一个字串,求输出的每个字串最小代价之和。

\(|T| \le 5 \times 10^{6}.\)

「1.2」思路简述

\(f(x)\) 表示输出到第 \(x\) 位时的最小代价,下面来考虑什么时候需要换手。

因为左右手都可以输入 B,所以当前位置为 B 的时候不需要换手,直接继承上一位的值,也就是 f(i) = f(i-1).

而当前位为 AC 时,对于上一个对应的 CA 的值,需要换手。

「1.3」Code

#include <iostream>
#include <stdio.h>
#include <cstring>

#define Heriko return
#define Deltana 0
#define Romanno 1
#define S signed
#define LL long long
#define R register
#define I inline
#define CI const int
#define mst(a, b) memset(a, b, sizeof(a))
#define ON std::ios::sync_with_stdio(false);cin.tie(0)
#define Files() freopen("RNMTQ.in","r",stdin);freopen("RNMTQ.out","w",stdout)

using namespace std;

CI MXX(5e6+1),MOD(998244353);

int ans,f[MXX],n,lsta,lstc;

char c[MXX];

S main()
{
    Files();
    ON;cin>>(c+1);n=strlen(c+1);

    for(int i(1);i<=n;++i)
        if(c[i]=='A') f[i]=(lstc+f[lstc])%MOD,lsta=i;
        else if(c[i]=='B') f[i]=f[i-1];
        else if(c[i]=='C') f[i]=(lsta+f[lsta])%MOD,lstc=i;

    for(int i(1);i<=n;++i) (ans+=f[i])%=MOD;

    cout<<(ans+MOD)%MOD;

    Heriko Deltana;
}

「2.0」\(n^3\) 过一万

然而标题好像只是暗示了这个题是个大约 \(O(n^3)\) 的题。

「2.1」题目简述

给出 \(n\) 个数(\(n\) 为偶数),每次可以删除相邻的两个数 \(a,b\),代价为 \(cost(a,b).\)

求问用 \(\frac{n}{2}\) 轮删完这些数字的代价最大值最小为多少?

「2.2」思路简述

这个问题的形式很明显需要二分答案了,那么我们对于每次二分的最大值行区间 DP。

f(l,r) 表示 \(l\)\(r\) 在最大值为能不能被删除,如果可以,就让 \(f(l,~) \operatorname{or} f(r+1,~).\)

因为都是一个布尔状态,所以可以用 bitset 来优化复杂度。

「2.3」Code

template<typename J>
I void fr(J &x)
{
    short f(1);x=0;char c=getchar();
    
    while(c<'0' or c>'9')
    {
        if(c=='-') f=-1;
        
        c=getchar();
    }
   
    while (c>='0' and c<='9') 
    {
        x=(x<<3)+(x<<1)+(c^=48);
       
        c=getchar();
    }
   
    x*=f;
}

template<typename J>
I void fw(J x,bool k)
{
    if(x<0) x=-x,putchar('-');
   
    static short stak[35];short top(0);
   
    do
    {
        stak[top++]=x%10;
        x/=10;
    }
    while(x);
   
    while(top) putchar(stak[--top]+'0');
   
    k?puts(""):putchar(' ');
}

CI MXX(4005);

bitset<MXX> f[MXX];

int a[MXX][MXX],n;

I bool Checker(int lmt)
{

    for(int l(n);l;--l)
        for(int r(l+1);r<=n;++r)
            if(f[l][r]) continue;
            else
            {
                if(r==l+1) f[l][r]=(a[l][r]<=lmt);
                else f[l][r]=(f[l+1][r-1]&(a[l][r]<=lmt));

                if(f[l][r]) f[l]|=f[r+1];
            }

    Heriko f[1][n];

}

S main()
{
    Files();
    mst(a,0x3f);fr(n);

    for(int i(1);i<=n;++i)
        for(int j(i+1);j<=n;j+=2)
            fr(a[i][j]);
    
    int l(1),r((n*n)>>2),ans(0);

    while(l<=r)
    {
        int mid((l+r)>>1);mst(f,0);

        if(Checker(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }

    fw(ans,1);

    Heriko Deltana;
}

「3.0」被 djq 加 0 了

咕着。

「4.0」加了三个零

不知道题目和题有啥关系,难道是数据范围加了三个零(?)

「4.1」题目简述

你有一个 \(1\)\(n\) 的排列 \(p1,p2,…,pn\)

现在你可以执行如下操作一次。

选择一个非负整数 \(k≥0\),和 \(2k\) 个端点 \(1≤l1<r1<l2<r2<⋯<lk<rk≤n\),然后对于每个 \(i\),我们都将 \(p_{l_{i}},p_{l_{i+1}},…,p_{r_{i}}\) 这些元素按升序排序。

问操作之后,可能可以得到多少种不同的排列。由于答案很大,输出对 \(998244353\) 取模的结果。

「4.2」Code

思路见代码罢。

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

CI MXX(2e5+5),MOD(998244353),INF(0x7fffffff);

int n,pw[MXX][20];

LL t[MXX];
    
#define lowbit(x) ((x)&(-x))

I void UPD(int x,int v) {while(x<=n) (t[x]+=v)%=MOD,x+=lowbit(x);}

I LL QUE(int x) 
{
    LL res(0);
    
    while(x) (res+=t[x])%=MOD,x-=lowbit(x);
    
    Heriko (res%MOD+MOD)%MOD;
}

I void Pre()
{
    for(int i(1);i<=n;++i) fr(pw[i][0]);
    
    for(int i(0);i<20;++i) pw[0][i]=INF;

    for(int j(1);j<20;++j)
        for(int i(1);i<=n;++i)
            if(i-(1<<j)+1>0) pw[i][j]=Hmax(pw[i][j-1],pw[i-(1<<(j-1))][j-1]);
            else pw[i][j]=INF;
}

LL f[MXX];

int s[MXX],fst;

S main()
{
    Files();
    fr(n);Pre();
    f[0]=1;UPD(1,1);

    for(int i(1);i<=n;++i)
    {
        while(fst and pw[s[fst]][0]>pw[i][0]) --fst;

        int now(s[fst]);

        for(int j(19);j>=0 and now>=0;--j)
            if(pw[now][j]<pw[i][0])
                now-=(1<<j);

        if(now<0) now=0;
        
        f[i]=((QUE(i)-QUE(s[fst]))%MOD+MOD)%MOD;

        if(now)
        {
            int val(lower_bound(s+1,s+1+fst,now)-s);
            f[i]=((f[i]+f[s[val]]-(QUE(s[val])-QUE(now)))%MOD+MOD)%MOD;
        }

        UPD(i+1,f[i]);s[++fst]=i;
    }

    fw(f[n],1);

    Heriko Deltana;
}

「5.0」尾声

也快 CSP 二轮了,但是为什么我还在爆零(?)

posted @ 2021-09-23 20:12  HerikoDeltana  阅读(43)  评论(0编辑  收藏  举报