8.26NOIP Day11模拟赛

T1

好像是一道小清新数据结构题,但我没管那么多直接就推了个性质开始贪了,最后打了一大坨

感性理解一下,挤压后区间长度跑满 \(d\) 一定是不劣的,同时显然最优情况一定是两个端点中存在一个被取到过至少一次

所以我们就考虑双指针跑一下决策区间,然后维护三种 \((<l,mid,>r)\) 之间相邻的贡献,分讨一大堆东西然后左右端点各跑一遍就完事了。

码长 \(2.5\) 倍,时间 \(1/15\),空间 \(1/20\),优势在我!

#include<bits/stdc++.h>
#define int long long
#define N 200005
using namespace std;
int x[N],y[N],id[N];
bool cmp(int a,int b){return x[a]<x[b];}
signed main(){
    int n,d;
    scanf("%lld%lld",&n,&d);
    for(int i=1;i<=n;i++){
        scanf("%lld",&x[i]);
        y[i]=i;
    }
    x[0]=x[1];
    x[n+1]=x[n];
    sort(y+1,y+n+1,cmp);
    for(int i=1;i<=n;i++)id[y[i]]=i;
    id[0]=id[1];
    id[n+1]=id[n];
    int cnt=0,now=1,ans=0,cnta=0,cntb=0,suma=0,sumb=0;
    for(int i=1;i<=n;i++){
        while(now<=n&&x[y[now]]<=x[y[i]]+d){
            int v=y[i],u=y[now];
            if(u>1){
                if(id[u-1]<id[v]){
                    cnt-=d;
                    cnta++;
                    suma+=x[u];
                }
                else if(id[u-1]<now){
                    cntb--;
                    sumb-=x[u-1];
                    cnt+=abs(x[u]-x[u-1]);
                }
                else{
                    cntb++;
                    sumb+=x[u];
                }
            }
            if(u<n){
                if(id[u+1]<id[v]){
                    cnt-=d;
                    cnta++;
                    suma+=x[u];
                }
                else if(id[u+1]<now){
                    cntb--;
                    sumb-=x[u+1];
                    cnt+=abs(x[u]-x[u+1]);
                }
                else{
                    cntb++;
                    sumb+=x[u];
                }
            }
            now++;
        }
        if(i>1){
            int u=y[i-1];
            if(u>1){
                if(id[u-1]<id[u]){
                    cnta--;
                    suma-=x[u];
                }
                else if(id[u-1]<now){
                    cnta++;
                    suma+=x[u-1];
                    cnt-=abs(x[u]-x[u-1]);
                }
                else{
                    cntb--;
                    sumb-=x[u];
                    cnt+=d;
                }
            }
            if(u<n){
                if(id[u+1]<id[u]){
                    cnta--;
                    suma-=x[u];
                }
                else if(id[u+1]<now){
                    cnta++;
                    suma+=x[u+1];
                    cnt-=abs(x[u]-x[u+1]);
                }
                else{
                    cntb--;
                    sumb-=x[u];
                    cnt+=d;
                }
            }
        }
        ans=max(ans,cnt+suma-cnta*x[y[i]]+cntb*(x[y[i]]+d)-sumb);
    }
    cnt=0;
    now=n;
    cnta=0;
    cntb=0;
    suma=0;
    sumb=0;
    for(int i=n;i;i--){
        while(now&&x[y[now]]>=x[y[i]]-d){
            int v=y[i],u=y[now];
            if(u>1){
                if(id[u-1]<now){
                    cnta++;
                    suma+=x[u];
                }
                else if(id[u-1]<id[v]){
                    cnta--;
                    suma-=x[u-1];
                    cnt+=abs(x[u]-x[u-1]);
                }
                else{
                    cnt-=d;
                    cntb++;
                    sumb+=x[u];
                }
            }
            if(u<n){
                if(id[u+1]<now){
                    cnta++;
                    suma+=x[u];
                }
                else if(id[u+1]<id[v]){
                    cnta--;
                    suma-=x[u+1];
                    cnt+=abs(x[u]-x[u+1]);
                }
                else{
                    cnt-=d;
                    cntb++;
                    sumb+=x[u];
                }
            }
            now--;
        }
        if(i<n){
            int u=y[i+1];
            if(u>1){
                if(id[u-1]<now){
                    cnt+=d;
                    cnta--;
                    suma-=x[u];
                }
                else if(id[u-1]<id[u]){
                    cntb++;
                    sumb+=x[u-1];
                    cnt-=abs(x[u]-x[u-1]);
                }
                else{
                    cntb--;
                    sumb-=x[u];
                }
            }
            if(u<n){
                if(id[u+1]<now){
                    cnt+=d;
                    cnta--;
                    suma-=x[u];
                }
                else if(id[u+1]<id[u]){
                    cntb++;
                    sumb+=x[u+1];
                    cnt-=abs(x[u]-x[u+1]);
                }
                else{
                    cntb--;
                    sumb-=x[u];
                }
            }
        }
        ans=max(ans,cnt+suma-cnta*(x[y[i]]-d)+cntb*x[y[i]]-sumb);
    }
    printf("%lld\n",ans);
    return 0;
}

T2

题目给出的是dfs序,再加上相邻叶结点连边,所以子树内只可能会有最左边和最右边的点连到外面去

考虑设计状态维护以每个子树内根节点是否匹配, 最左边的叶⼦是否匹配,最右边的叶⼦是否匹配的⽅案数,然后巨大分讨

#include<bits/stdc++.h>
#define mod 998244353
#define N 100005
#define int long long
using namespace std;
int fa[N],dp[N][2][2][2],f[N][2][2][2],R[N];
signed main(){
    int n;
    scanf("%lld",&n);
    for(int i=2;i<=n;i++)scanf("%lld",&fa[i]);
    for(int i=n;i>=1;i--)R[i]=i;
    for(int i=n;i>=1;i--)R[fa[i]]=max(R[fa[i]],R[i]);
    for(int i=1;i<=n;i++)if(i==R[i])dp[i][0][0][0]=dp[i][1][1][0]=dp[i][1][0][1]=1;
    for(int i=n;i>=2;i--){
        int u=i,v=fa[i];
        if(R[u]==R[v]){
            dp[v][0][0][0]=(dp[u][0][0][0]+dp[u][1][0][0])%mod;
            dp[v][0][0][1]=(dp[u][0][0][1]+dp[u][1][0][1])%mod;
            dp[v][0][1][0]=(dp[u][0][1][0]+dp[u][1][1][0])%mod;
            dp[v][0][1][1]=(dp[u][0][1][1]+dp[u][1][1][1])%mod;
            dp[v][1][0][0]=dp[u][0][0][0];
            dp[v][1][0][1]=dp[u][0][0][1];
            dp[v][1][1][0]=dp[u][0][1][0];
            dp[v][1][1][1]=dp[u][0][1][1];
        }
        else{
            f[v][0][0][0]=(dp[v][0][0][0]*dp[u][0][0][0]+dp[v][0][1][0]*dp[u][0][0][1]+dp[v][0][0][0]*dp[u][1][0][0]+dp[v][0][1][0]*dp[u][1][0][1])%mod;
            f[v][0][0][1]=(dp[v][0][0][1]*dp[u][0][0][0]+dp[v][0][1][1]*dp[u][0][0][1]+dp[v][0][0][1]*dp[u][1][0][0]+dp[v][0][1][1]*dp[u][1][0][1])%mod;
            f[v][0][1][0]=(dp[v][0][0][0]*dp[u][0][1][0]+dp[v][0][1][0]*dp[u][0][1][1]+dp[v][0][0][0]*dp[u][1][1][0]+dp[v][0][1][0]*dp[u][1][1][1])%mod;
            f[v][0][1][1]=(dp[v][0][0][1]*dp[u][0][1][0]+dp[v][0][1][1]*dp[u][0][1][1]+dp[v][0][0][1]*dp[u][1][1][0]+dp[v][0][1][1]*dp[u][1][1][1])%mod;
            f[v][1][0][0]=(dp[v][0][0][0]*dp[u][0][0][0]+dp[v][0][1][0]*dp[u][0][0][1]+dp[v][1][0][0]*dp[u][0][0][0]+dp[v][1][1][0]*dp[u][0][0][1]+dp[v][1][0][0]*dp[u][1][0][0]+dp[v][1][1][0]*dp[u][1][0][1])%mod;
            f[v][1][0][1]=(dp[v][0][0][1]*dp[u][0][0][0]+dp[v][0][1][1]*dp[u][0][0][1]+dp[v][1][0][1]*dp[u][0][0][0]+dp[v][1][1][1]*dp[u][0][0][1]+dp[v][1][0][1]*dp[u][1][0][0]+dp[v][1][1][1]*dp[u][1][0][1])%mod;
            f[v][1][1][0]=(dp[v][0][0][0]*dp[u][0][1][0]+dp[v][0][1][0]*dp[u][0][1][1]+dp[v][1][0][0]*dp[u][0][1][0]+dp[v][1][1][0]*dp[u][0][1][1]+dp[v][1][0][0]*dp[u][1][1][0]+dp[v][1][1][0]*dp[u][1][1][1])%mod;
            f[v][1][1][1]=(dp[v][0][0][1]*dp[u][0][1][0]+dp[v][0][1][1]*dp[u][0][1][1]+dp[v][1][0][1]*dp[u][0][1][0]+dp[v][1][1][1]*dp[u][0][1][1]+dp[v][1][0][1]*dp[u][1][1][0]+dp[v][1][1][1]*dp[u][1][1][1])%mod;
            dp[v][0][0][0]=f[v][0][0][0];
            dp[v][0][0][1]=f[v][0][0][1];
            dp[v][0][1][0]=f[v][0][1][0];
            dp[v][0][1][1]=f[v][0][1][1];
            dp[v][1][0][0]=f[v][1][0][0];
            dp[v][1][0][1]=f[v][1][0][1];
            dp[v][1][1][0]=f[v][1][1][0];
            dp[v][1][1][1]=f[v][1][1][1];
        }
    }
    printf("%lld\n",(dp[1][0][0][0]+dp[1][0][1][1]+dp[1][1][0][0]+dp[1][1][1][1])%mod);
    return 0;
}

T3

忘了,好像是要写网络流

T4

忘了,怎么又是生成函数

posted @ 2025-08-26 11:11  Igunareo  阅读(9)  评论(0)    收藏  举报