多校A层冲刺NOIP2024模拟赛25

多校A层冲刺NOIP2024模拟赛25

T1 A. 图 100pts/100pts

  • 对于每个状态开一个 bitset 加速位运算即可。

    点击查看代码
    bitset<10010>vis[10010],tmp[4];
    char s[10010];
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
    #endif
        int n,m,ans=0,i,j,k;
        cin>>n>>m;
        for(k=1;k<=m;k++)
        {
            cin>>(s+1);
            for(i=1;i<=3;i++)
            {
                tmp[i].reset();
            }
            for(i=n;i>=1;i--)
            {
                if(s[i]=='1')
                {
                    vis[i]^=tmp[2];
                    vis[i]^=tmp[3];
                }
                if(s[i]=='2')
                {
                    vis[i]^=tmp[1];
                    vis[i]^=tmp[3];
                }
                if(s[i]=='3')
                {
                    vis[i]^=tmp[1];
                    vis[i]^=tmp[2];
                    vis[i]^=tmp[3];
                }
                tmp[s[i]-'0'][i]=1;
            }
        }
        for(i=1;i<=n;i++)
        {
            ans+=vis[i].count();
        }
        cout<<ans<<endl;
        return 0;
    }
    

T2 B. 序列 0pts/0pts

  • 考虑将所有操作表示成 ai 乘以一个系数的形式。

    • 赋值仅考虑赋值后的最大值 ymax ,将其转换成 ymaxai 的形式(先不用管正负号的问题)。
    • 加一定是先加较大的数再加较小的数,不妨先降序排序,其贡献为 ai+ytai ,其中 ai=ai+j=1t1yj
    • 乘直接处理即可。
  • 将贡献扔到操作序列上降序排序即可。

  • 因为可能存在 ai0(mod10000000007) 的情况,所以可以把答案中的 109+7 的指数单独提出去(另外可以证明只会非负整数)。

    点击查看代码
    const ll p=1000000007;
    ll a[100010],maxx[100010],last[100010];
    vector<ll>sum[100010];
    vector<pair<__int128_t,__int128_t> >c;
    bool cmp(pair<__int128_t,__int128_t>a,pair<__int128_t,__int128_t>b)
    {
        return a.first*b.second>b.first*a.second;
    }
    ll qpow(ll a,ll b,ll p)
    {
        ll ans=1;
        while(b)
        {
            if(b&1)
            {
                ans=ans*a%p;
            }
            b>>=1;
            a=a*a%p;
        }
        return ans;
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("b.in","r",stdin);
        freopen("b.out","w",stdout);
    #endif
        ll n,m,t,x,y,ans=1,cnt=0,i,j;
        cin>>n>>m;
        for(i=1;i<=n;i++)
        {
            cin>>a[i];
            ans=ans*a[i]%p;
        }
        for(i=1;i<=m;i++)
        {
            cin>>t>>x>>y;
            if(t==1)
            {
                maxx[x]=max(maxx[x],y);
            }
            if(t==2)
            {
                sum[x].push_back(y);
            }
            if(t==3)
            {
                c.push_back(make_pair(y,1));
            }
        }
        for(i=1;i<=n;i++)
        {
            if(maxx[i]>a[i])
            {
                sum[i].push_back(maxx[i]-a[i]);
            }
            sort(sum[i].begin(),sum[i].end(),greater<ll>());
            for(j=0;j<sum[i].size();j++)
            {
                c.push_back(make_pair(a[i]+sum[i][j],a[i]));
                a[i]+=sum[i][j];
            }
        }
        sort(c.begin(),c.end(),cmp);
        for(i=0;i<=m;i++)
        {
            cout<<(cnt==0)*ans<<" ";
            if(i<c.size())
            {
                if(c[i].first%p==0)
                {
                    c[i].first/=p;
                    cnt++;
                }
                if(c[i].second%p==0)
                {
                    c[i].second/=p;
                    cnt--;
                }
                ans=(ans*(c[i].first%p)%p)*qpow(c[i].second%p,p-2,p)%p;
            }
        }
        return 0;
    }
    

T3 C. 树 10pts/0pts

  • 部分分

    • 20pts :暴力连边然后进行博弈,时间复杂度为 n2d+1d
    点击查看代码
    const ll p=1000000007;
    int ans;
    vector<int>e[8000010];
    void add(int u,int v)
    {
        e[u].push_back(v);
    }
    int ask(int x,int fa)
    {
        for(int i=0;i<e[x].size();i++)
        {
            if(e[x][i]!=fa&&ask(e[x][i],x)==0)
            {
                return 1;
            }
        }
        return 0;
    }
    void dfs(int pos,int d,int n)
    {
        if(pos==d+1)
        {
            ans=(ans+ask(1,0))%p;
        }
        else
        {
            for(int i=1+(pos-1)*n;i<=pos*n;i++)
            {
                for(int j=1+pos*n;j<=(pos+1)*n;j++)
                {
                    e[i].push_back(j);
                    dfs(pos+1,d,n);
                    e[i].pop_back();
                }
            }
        }
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("c.in","r",stdin);
        freopen("c.out","w",stdout);
    #endif
        int n,d,u,v,i,j;
        cin>>n>>d;
        for(j=1;j<=n-1;j++)
        {
            cin>>u>>v;
            for(i=0;i<=d;i++)
            {
                add(u+i*n,v+i*n);
                add(v+i*n,u+i*n);
            }
        }
        dfs(1,d,n);
        cout<<ans<<endl;
        return 0;
    }
    
  • 正解

T4 D. 字符串 0pts/0pts

  • 部分分

    • 10pts :双指针判断是否需要插入,写法和判断一个数列是否是另一个数列的子序列差不多。
  • 正解

    • 对每个字符按照 t 中位置进行编号,然后等价于查询 [l,r] 中极长严格递增段的个数加 1 。考虑统计断点(相邻两个字符逆序)的个数。
    • 观察到 k[1,10] ,所以直接对着值域挂在线段树的每个节点上就行了。
    点击查看代码
    int k,tmp[11][11],id[11];
    char s[200010],t[25];
    struct SMT
    {
        struct SegmentTree
        {
            int lc,rc,sum[11][11],lazy;
            SegmentTree()
            {
                lc=rc=lazy=0;
                memset(sum,0,sizeof(sum));
            }
            SegmentTree operator + (const SegmentTree &another)
            {	
                SegmentTree tmp;
                for(int i=1;i<=k;i++)
                {
                    for(int j=1;j<=k;j++)
                    {
                        tmp.sum[i][j]=sum[i][j]+another.sum[i][j];
                    }
                }
                tmp.sum[rc][another.lc]++;
                tmp.lc=lc;
                tmp.rc=another.rc;
                return tmp;
            }
        }tree[800010];
        int lson(int x)
        {
            return x*2;
        }
        int rson(int x)
        {
            return x*2+1;
        }
        void pushup(int rt)
        {
            tree[rt]=tree[lson(rt)]+tree[rson(rt)];
        }
        void build(int rt,int l,int r)
        {
            if(l==r)
            {
                tree[rt].lc=tree[rt].rc=s[l]-'a'+1;
                return;
            }
            int mid=(l+r)/2;
            build(lson(rt),l,mid);
            build(rson(rt),mid+1,r);
            pushup(rt);
        }
        int move_right(int x,int d)
        {
            return (x+d-1)%k+1;
        }
        void pushlazy(int rt,int lazy)
        {
            tree[rt].lc=move_right(tree[rt].lc,lazy);
            tree[rt].rc=move_right(tree[rt].rc,lazy);
            for(int i=1;i<=k;i++)
            {
                for(int j=1;j<=k;j++)
                {
                    tmp[move_right(i,lazy)][move_right(j,lazy)]=tree[rt].sum[i][j];
                }
            }
            for(int i=1;i<=k;i++)
            {
                for(int j=1;j<=k;j++)
                {
                    tree[rt].sum[i][j]=tmp[i][j];
                }
            }
            tree[rt].lazy=(tree[rt].lazy+lazy)%k;
        }
        void pushdown(int rt)
        {
            if(tree[rt].lazy!=0)
            {
                pushlazy(lson(rt),tree[rt].lazy);
                pushlazy(rson(rt),tree[rt].lazy);
                tree[rt].lazy=0;
            }
        }
        void update(int rt,int l,int r,int x,int y,int val)
        {
            if(x<=l&&r<=y)
            {
                pushlazy(rt,val);
                return;
            }
            pushdown(rt);
            int mid=(l+r)/2;
            if(x<=mid)
            {
                update(lson(rt),l,mid,x,y,val);
            }
            if(y>mid)
            {
                update(rson(rt),mid+1,r,x,y,val);
            }
            pushup(rt);
        }
        SegmentTree query(int rt,int l,int r,int x,int y)
        {
            if(x<=l&&r<=y)
            {
                return tree[rt];
            }
            pushdown(rt);
            int mid=(l+r)/2;
            if(y<=mid)
            {
                return query(lson(rt),l,mid,x,y);
            }
            if(x>mid)
            {
                return query(rson(rt),mid+1,r,x,y);
            } 
            return query(lson(rt),l,mid,x,y)+query(rson(rt),mid+1,r,x,y);
        }
        int ask(int l,int r,int n)
        {
            int sum=1;
            SegmentTree tmp=query(1,1,n,l,r);
            for(int i=1;i<=k;i++)
            {
                id[t[i]-'a'+1]=i;
            }
            for(int i=1;i<=k;i++)
            {
                for(int j=1;j<=k;j++)
                {
                    sum+=(id[i]>=id[j])*tmp.sum[i][j];
                }
            }
            return sum;
        }
    }T;
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("d.in","r",stdin);
        freopen("d.out","w",stdout);
    #endif
        int n,m,pd,l,r,c,i;
        cin>>n>>m>>k>>(s+1);
        T.build(1,1,n);
        for(i=1;i<=m;i++)
        {
            cin>>pd>>l>>r;
            if(pd==1)
            {
                cin>>c;
                T.update(1,1,n,l,r,c);
            }
            else
            {
                cin>>(t+1);
                cout<<T.ask(l,r,n)<<endl;
            }
        }
        return 0;
    }
    

总结

  • T2
    • 读假题了,把 至多 读成 恰好 了。
    • 又没想到转化到操作序列上排序,一直在想对某个单体怎么处理。
  • T3 理解错了有根树的含义,以为复制后的树中仍需满足原上下级关系,挂了 10pts
  • T4 赛时降智了,导致不会写判断一个数列是否是另一个数列的子序列。

后记

  • T1 的提示不知道有什么用。

  • T3 中途补充了大样例。

posted @   hzoi_Shadow  阅读(80)  评论(14编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
扩大
缩小
点击右上角即可分享
微信分享提示