多校A层冲刺NOIP2024模拟赛27终结篇

不知道是不是我打的最后一场模拟赛了,记录一下吧,总体来说还不错,虽然 \(T1\) 方案数求错爆零了,但 \(T3\) 场切了,暴力打满的话有265,希望 \(NOIP\) 时也可以不让自己遗憾吧。

——我们终会在星辰里相遇

A 【模板】分治FFT

考虑每加进来一个数的贡献 \(x_1*x_2+(x_1+x_2)*x_3+...=x_1*x_2+x_1*x_3+x_2*x_3+...\) 可以发现实际上不管怎么取都是每两个数相乘的和,所以直接一种方案的答案乘方案书即可,每次合并时少一堆,所以方案数是 $\sum \limits_{i=2}^{n} \dbinom{i}{2} $。

点击查看代码
#include<bits/stdc++.h>
#define int long long
const int mod=998244353;
const int maxn=1e5+10;
using namespace std;
int n,a[maxn],sum[maxn],ans,jc[maxn];

int qpow(int x,int y)
{
    int ans=1;
    while(y)
    {
        if(y&1) ans=ans*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ans;
}

int c(int n,int m)
{
    return jc[n]*qpow(jc[m],mod-2)%mod*qpow(jc[n-m],mod-2)%mod;
}

signed main()
{
    freopen("fft.in","r",stdin);
    freopen("fft.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n;
    jc[0]=1;
    for(int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=n;i>=1;i--) sum[i]=(sum[i+1]+a[i])%mod;
    for(int i=1;i<=n;i++) ans=(ans+a[i]*sum[i+1]%mod)%mod;
    int temp=c(n,2);
    for(int i=1;i<=n-2;i++) temp=temp*c(n-i,2)%mod;
    cout<<ans*temp%mod;;


    return 0;
}
/*
2
100001 100002
*/

B 【模板】最近公共祖先

构造,但是我没仔细推,我觉得题解说的很好,所以直接放了
image

点击查看代码
#include<bits/stdc++.h>
const int maxn=3e5+10;
using namespace std;
int n,m,cnt,dep[maxn];
int head[maxn],to[maxn<<1],nxt[maxn<<1],tot;
vector<int> s[maxn],t[maxn];
bool vis[maxn];
struct lsx
{
    int x,y,z;
}ans[maxn];
void add(int x,int y)
{
    to[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}
void addm(int x,int y)
{
    add(x,y),add(y,x);
}

void lsx(int x)
{
    vis[x]=1;
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(vis[y])
        {
            if(dep[y]<dep[x]) s[x].push_back(y);
        }
        else dep[y]=dep[x]+1,lsx(y);
    }
    while(t[x].size()>1)
    {
        int p=t[x].back();t[x].pop_back();
        ans[++cnt]={p,x,t[x].back()};
        t[x].pop_back();
    }
    while(t[x].size()&&s[x].size())
    {
        ans[++cnt]={t[x].back(),x,s[x].back()};
        s[x].pop_back(),t[x].pop_back();
    }
    for(auto i:s[x]) t[i].push_back(x);
}

int main()
{
    freopen("lca.in","r",stdin);
    freopen("lca.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1,x,y;i<=m;i++)
       cin>>x>>y,addm(x,y);
    for(int i=1;i<=n;i++) if(!vis[i]) lsx(i);
    cout<<cnt<<'\n';
    for(int i=1;i<=cnt;i++) cout<<ans[i].x<<" "<<ans[i].y<<" "<<ans[i].z<<'\n';

    return 0;
}
/*

*/

C 【模板】普通平衡树

关于我题解没看懂这件事,考虑新加进来一个数的贡献,由于保证了互不相同,所以新加进来一个数它要么使序列更长,要么就是替换掉最后一个数使值域差更大,每次更改只和最后两个数的值有关,直接对每个序列维护最后两个数的值和答案即可,暴力是 \(O(nq)\) 的,考虑线段树优化这个过程,两个序列段合并时发现,答案只和两个序列段边界的两个值的关系有关,所以线段树直接维护每个序列段最前面的两个数的值,最后面的两个数的值,序列长度,序列答案即可,合并的时候直接分讨边界四个数的大小关系即可,需要特判序列长度小于等于2时的情况。

点击查看代码
#include<bits/stdc++.h>
#define lid id<<1
#define rid id<<1|1
#define mid (l+r>>1)
const int maxn=3e5+10;
using namespace std;
int n,q;
struct lsx
{
    int fi[3],en[3],size,ans,lazy;
}m[maxn<<2],mm;

void add(int id,int x)
{
    if(!m[id].size)
    {
        m[id].size++;
        m[id].fi[1]=m[id].en[1]=x;
        m[id].ans=1;
    }
    else if(m[id].size==1)
    {
        m[id].size++;
        m[id].fi[2]=m[id].en[2]=x;
        m[id].ans=2;
    }
    else
    {
        if(m[id].en[1]>m[id].en[2])
        {
            if(x>m[id].en[2])
            {
                m[id].en[1]=m[id].en[2];
                m[id].en[2]=x;
                m[id].ans++;
            }
            else
            {
                if(m[id].size==2)m[id].fi[2]=x;
                m[id].en[2]=x;
            }
        }
        else
        {
            if(x<m[id].en[2])
            {
                m[id].en[1]=m[id].en[2];
                m[id].en[2]=x;
                m[id].ans++;
            }
            else
            {
                if(m[id].size==2)m[id].fi[2]=x;
                m[id].en[2]=x;
            }
        }
        m[id].size++;
    }
}

void solve(int x,int id)
{
    mm=m[x];
    if(mm.size==1)
    {
        add(id,mm.fi[1]);
        return ;
    }
    if(!m[id].size)
    {
        m[id].size=mm.size;
        m[id].fi[1]=mm.fi[1];
        m[id].fi[2]=mm.fi[2];
        m[id].en[1]=mm.en[1];
        m[id].en[2]=mm.en[2];
        m[id].ans=mm.ans;
    }
    else if(m[id].size==1)
    {
        if(mm.fi[1]<mm.fi[2])
        {
            if(m[id].fi[1]<mm.fi[1])
            {
                mm.fi[1]=m[id].fi[1];
                m[id].size=mm.size;
                m[id].fi[1]=mm.fi[1];
                m[id].fi[2]=mm.fi[2];
                m[id].en[1]=mm.en[1];
                m[id].en[2]=mm.en[2];
                m[id].ans=mm.ans;
            }
            else
            {
                mm.size++,mm.ans++;
                mm.fi[2]=mm.fi[1];
                mm.fi[1]=m[id].fi[1];
                m[id].size=mm.size;
                m[id].fi[1]=mm.fi[1];
                m[id].fi[2]=mm.fi[2];
                m[id].en[1]=mm.en[1];
                m[id].en[2]=mm.en[2];
                m[id].ans=mm.ans;
            }
        }
        else
        {
            if(m[id].fi[1]>mm.fi[1])
            {
                mm.fi[1]=m[id].fi[1];
                m[id].size=mm.size;
                m[id].fi[1]=mm.fi[1];
                m[id].fi[2]=mm.fi[2];
                m[id].en[1]=mm.en[1];
                m[id].en[2]=mm.en[2];
                m[id].ans=mm.ans;
            }
            else
            {
                mm.size++,mm.ans++;
                mm.fi[2]=mm.fi[1];
                mm.fi[1]=m[id].fi[1];
                m[id].size=mm.size;
                m[id].fi[1]=mm.fi[1];
                m[id].fi[2]=mm.fi[2];
                m[id].en[1]=mm.en[1];
                m[id].en[2]=mm.en[2];
                m[id].ans=mm.ans;
            }
        }
    }
    else
    {
        if(m[id].en[1]>m[id].en[2])
        {
            if(mm.fi[1]<mm.fi[2])
            {
                if(mm.size==2) mm.en[1]=min(mm.en[1],m[id].en[2]);
                m[id].size+=mm.size-1;
                m[id].ans+=mm.ans-1;
                m[id].en[1]=mm.en[1],m[id].en[2]=mm.en[2];
            }
            else
            {
                if(m[id].en[2]<mm.fi[1])
                {
                    m[id].size+=mm.size;
                    m[id].ans+=mm.ans;
                    m[id].en[1]=mm.en[1],m[id].en[2]=mm.en[2];
                }
                else
                {
                    if(mm.size==2) mm.en[1]=m[id].en[1];
                    m[id].size+=mm.size-2;
                    m[id].ans+=mm.ans-2;
                    m[id].en[1]=mm.en[1],m[id].en[2]=mm.en[2];
                }
            }
        }
        else
        {
            if(mm.fi[1]>mm.fi[2])
            {
                if(mm.size==2) mm.en[1]=max(mm.en[1],m[id].en[2]);
                m[id].size+=mm.size-1;
                m[id].ans+=mm.ans-1;
                m[id].en[1]=mm.en[1],m[id].en[2]=mm.en[2];
            }
            else
            {
                if(m[id].en[2]>mm.fi[1])
                {
                    m[id].size+=mm.size;
                    m[id].ans+=mm.ans;
                    m[id].en[1]=mm.en[1],m[id].en[2]=mm.en[2];
                }
                else
                {
                    if(mm.size==2) mm.en[1]=m[id].en[1];
                    m[id].size+=mm.size-2;
                    m[id].ans+=mm.ans-2;
                    m[id].en[1]=mm.en[1],m[id].en[2]=mm.en[2];
                }
            }
        }
    }
}

void down(int id)
{
    if(!m[id].lazy) return ;
    solve(id,lid);
    solve(id,rid);
    m[lid].lazy=m[rid].lazy=1;
    m[id].lazy=m[id].size=m[id].ans=m[id].fi[1]=m[id].fi[2]=m[id].en[1]=m[id].en[2]=0;
}

void update(int id,int l,int r,int s,int t,int x)
{
    if(l>=s&&r<=t)
    {
        m[id].lazy=1;
        add(id,x);
        return ;
    }
    down(id);
    if(mid>=s) update(lid,l,mid,s,t,x);
    if(mid<t) update(rid,mid+1,r,s,t,x);
}

int query(int id,int l,int r,int x)
{
    // cout<<l<<" "<<r<<" "<<x<<endl;
    if(l==r) return m[id].ans;
    down(id);
    return x<=mid?query(lid,l,mid,x):query(rid,mid+1,r,x);
}

int main()
{
    freopen("odt.in","r",stdin);
    freopen("odt.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>q;
    while(q--)
    {
        int op,l,r,x;
        cin>>op;
        if(op==1)
        {
            cin>>l>>r>>x;
            update(1,1,n,l,r,x);
        }
        else
        {
            cin>>x;
            cout<<query(1,1,n,x)<<'\n';
        }
    }


    return 0;
}
/*
10 4
1 6 6 697
1 4 8 824
1 6 7 455
2 7

*/

stars

image
image
image
image
image
image
image
image
image
image
image
image

posted @ 2024-11-28 20:03  _君の名は  阅读(31)  评论(2编辑  收藏  举报