ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

NOI模拟24

2022-06-13 19:31:30  阅读:222  来源: 互联网

标签:24 ch ma NOI mb int tr 模拟 fo


垫底加啥也不是,但是感觉啥都会呵呵呵

原题,不多说什么,做T1的时间有点多了,T2就只有暴力,没怎么化式子,T3就没有写...

T1 CF590E

这里就一个知识点,有关于有向无环图的最大独立集问题

既然是有向无环图,这个东西的最大独立集也就是最长反链等于最小可重链划分

于是这个不太好搞,于是把有向无环图用Floyd跑一下传递闭包,于是变成了偏序集,用dilworth定理就是最小链划分了

拆点,然后跑网络流就行了,我们想要构造最长反链的方案

我们知道最长反链也就是最大独立集等于最小点覆盖的补集,我们想要找到最小点覆盖,取补集就是最大独立集了

我们从拆出来的右侧的点中没有匹配的点开始搜,从右向左走非匹配边,从左向右走匹配边

这时候我们要左侧被搜到的点,右侧未被搜到的点,这些就是二分图的最小点覆盖,为什么

对于匹配边来说,如果选了左侧的点,也就说左侧的点被搜到了,那么经过这个边一定可以搜到右侧对应的点,于是右边就不选了,相反,如果左侧未搜到,那么右侧也搜不到,于是就选上了右边的点

对于非匹配边来说,如果右侧是非匹配点的话,那么走这条边就可以走到左边,于是选上了左边的点,右侧若是匹配点,那么左侧一定是非匹配点,如果右侧被搜到,那么左侧也可以被搜到,如果右侧没有被搜到,那么就选右边的点喽

于是残量网络上这样搞一搞我们就找到了最小点覆盖,但是这是拆完点之后的啊,咋弄回去,不会!

我们先取补集,然后在两侧都是补集的点就是原图的最长反链上的点

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
    return s*t;
}
const int N=755;
const int M=1e7+5;
const int inf=0x3f3f3f3f;
int n;char ch[M];vector<char> s[N];
int tail[N],id[N],sz[N];
bool com(int x,int y){return sz[x]<sz[y];}
struct AC{
    struct POT{int son[2],fail;}tr[M];
    int seg,dfn[M],dfm[M],cnt,id[M],sz[M],cid;
    queue<int> q;
    void build(){
        fo(i,0,1)if(tr[0].son[i])q.push(tr[0].son[i]);
        while(!q.empty()){
            int x=q.front();q.pop();
            id[++cid]=x;
            fo(i,0,1){
                if(tr[x].son[i])tr[tr[x].son[i]].fail=tr[tr[x].fail].son[i],q.push(tr[x].son[i]);
                else tr[x].son[i]=tr[tr[x].fail].son[i];
            }
        }
        fu(i,cid,1){
            int x=id[i];
            sz[x]++;
            sz[tr[x].fail]+=sz[x];
        }
        sz[0]++;dfn[0]=1;dfm[0]=sz[0];
        fo(i,1,cid){
            int x=id[i];
            dfn[x]=dfn[tr[x].fail]+1;
            dfm[x]=dfn[x]+sz[x]-1;
            dfn[tr[x].fail]+=sz[x];
        }
        fo(i,0,cid)dfn[i]=dfm[i]-sz[i]+1;
    }
}ac;
struct BIT{
    int tr[M];
    inline void ins(int x){
        for(int i=x;i<=ac.seg+1;i+=(i&-i))tr[i]++;
    }
    inline void clr(int x){
        for(int i=x;i<=ac.seg+1&&tr[i];i+=(i&-i))tr[i]=0;
    }
    inline int qry(int x){
        int ret=0;
        for(int i=x;i;i-=(i&-i))ret+=tr[i];
        return ret;
    }
    inline int qey(int l,int r){
        return qry(r)-qry(l-1);
    }
}bit;
int ie[N];
struct NET{
    struct E{int to,nxt,val;}e[N*N*3];
    int head[N*2],hea[N*2],rp=1,s,t;
    void add_edg(int x,int y,int z){
        e[++rp].to=y;e[rp].nxt=head[x];
        e[rp].val=z;head[x]=rp;
    }
    int dis[N*2];
    bool bfs(){
        memcpy(head,hea,sizeof(int)*(n*2+5));
        memset(dis,0x3f,sizeof(int)*(n*2+5));
        queue<int> q;while(!q.empty())q.pop();
        q.push(s);dis[s]=0;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=e[i].nxt){
                int y=e[i].to;
                if(!e[i].val||dis[y]<=dis[x]+1)continue;
                dis[y]=dis[x]+1;q.push(y);
                if(y==t)return true;
            }
        }return false;
    }
    int dfs(int x,int in){
        if(x==t)return in;
        int rest=in,go;
        for(int i=head[x];i;head[x]=i=e[i].nxt){
            int y=e[i].to;
            if(!e[i].val||dis[y]!=dis[x]+1)continue;
            go=dfs(y,min(e[i].val,rest));
            if(go)rest-=go,e[i].val-=go,e[i^1].val+=go;
            else dis[y]=0;
            if(!rest)break;
        }return in-rest;
    }
    int dinic(){
        memcpy(hea,head,sizeof(int)*(n*2+5));
        int ret=0;
        while(bfs())ret+=dfs(s,inf);
        return ret;
    }
    bool vis[N*2];
    void pdfs(int x){
        if(vis[x]||x==t||x==s)return ;vis[x]=true;
        for(int i=head[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(e[i].val)continue;
            pdfs(y);
        }
    }
    void print(){
        memcpy(head,hea,sizeof(head));
        fo(i,1,n)if(e[ie[i]].val)pdfs(i*2);
        fo(i,1,n)if(!vis[i*2-1]&&vis[i*2])printf("%d ",i);
    }
}net;
signed main(){
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    n=read();
    int sm=0;bool flag=false;
    fo(i,1,n){
        scanf("%s",ch+1);sz[i]=strlen(ch+1);
        fo(j,1,sz[i])s[i].push_back(ch[j]);
        int now=0;
        for(char ss:s[i]){
            if(!ac.tr[now].son[ss-'a'])ac.tr[now].son[ss-'a']=++ac.seg;
            now=ac.tr[now].son[ss-'a'];
        }tail[i]=now;
        if(i==4&&ch[1]=='b'&&ch[2]=='b'&&sz[i]==2)flag=true;
    }
    ac.build();
    fo(i,1,n){
        int now=0;
        for(char ss:s[i]){
            now=ac.tr[now].son[ss-'a'];
            bit.ins(ac.dfn[now]);
        }
        fo(j,1,n)if(sz[j]<sz[i]){
            if(bit.qey(ac.dfn[tail[j]],ac.dfm[tail[j]])){
                // assert()
                // if(flag&&i==58)cout<<j<<" ";
                net.add_edg(j*2-1,i*2,1);
                net.add_edg(i*2,j*2-1,0);
            }
        }
        // if(flag&&i==58)cout<<endl;
        now=0;
        for(char ss:s[i]){
            now=ac.tr[now].son[ss-'a'];
            bit.clr(ac.dfn[now]);
        }
    }
    net.s=2*n+1;net.t=2*n+2;
    fo(i,1,n){
        net.add_edg(net.s,i*2-1,1);net.add_edg(i*2-1,net.s,0);
        net.add_edg(i*2,net.t,1);
        ie[i]=net.rp;
        net.add_edg(net.t,i*2,0);
    }
    printf("%d\n",n-net.dinic());
    net.print();
}

T2 AGC031D

对于一个变换我们将之变为先从\(p_i\)映射回\(i\),再从\(i\)映射到\(q_i\)

于是这里涉及到一个知识,对于一个矩阵\(A*B*C*D\)来说,它的逆矩阵是\(D^{-1}*C^{-1}*B^{-1}*A^{-1}\)

于是我们推着推着发现增量出现了循环节

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
    return s*t;
}
const int N=1e5+5;
int n,m;
struct node{
    int x[N];
    node(){fo(i,1,n)x[i]=i;}
    node operator * (node a)const{
        node ret=*this;
        fo(i,1,n)ret.x[i]=a.x[ret.x[i]];
        return ret;
    }
    void print(){
        fo(i,1,n)printf("%d ",x[i]);
        printf("\n");
    }
}pa,pb,qa,qb,ma,mb,xa,xb;
node nksm(node x,int y){
    node ret;
    while(y){
        if(y&1)ret=ret*x;
        x=x*x;y>>=1;
    }return ret;
}
signed main(){
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
    n=read();m=read();
    fo(i,1,n)pa.x[i]=read(),pb.x[pa.x[i]]=i;
    fo(i,1,n)qa.x[i]=read(),qb.x[qa.x[i]]=i;
    if(m==1)return pa.print(),0;m-=2;
    fo(i,1,n)ma.x[i]=i;mb=qa;
    xa=qb*pa*qa*pb;xb=qa*pa*qb*pb;
    ma=ma*nksm(xa,m/6);
    mb=nksm(xb,m/6)*mb;
    if(m%6>=1)mb=pb*mb;
    if(m%6>=2)ma=ma*qb;
    if(m%6>=3)ma=ma*pa,mb=qb*mb;
    if(m%6>=4)mb=pa*mb;
    if(m%6>=5)ma=ma*qa;
    if(m%6>=6)ma=ma*pb,mb=qa*mb;
    (ma*mb).print();
}

T3 AGC026E

结论题,不在多说,用string转移即可!!

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
    return s*t;
}
const int N=3005;
int n;
int pa[N],pb[N],ca,cb,id[N*2];
string f[N],s;
signed main(){
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    n=read();cin>>s;s=' '+s;
    fo(i,1,2*n){
        if(s[i]=='a')pa[id[i]=++ca]=i;
        else pb[id[i]=++cb]=i;
    }
    pa[n+1]=pb[n+1]=2*n+1;id[2*n+1]=n+1;
    fu(i,n,1){
        f[i]=f[i+1];
        if(pa[i]<pb[i]){
            fo(j,i+1,n+1)if(pa[j]>pb[i]&&pb[j]>pb[i]){
                // cerr<<j<<" "<<"ab"+f[j]<<endl;
                f[i]=max(f[i],"ab"+f[j]);
                break;
            }
        }
        else {
            int now=1;string st="b";
            fo(j,pb[i]+1,2*n){
                if(id[j]<i)continue;
                if(s[j]=='a'){
                    now--;st+='a';
                    if(!now){
                        now=j+1;
                        break;
                    }
                }
                else {
                    now++;st+='b';
                }
            }
            // cerr<<now<<endl;
            f[i]=max(f[i],st+f[id[now]]);
        }
        // cout<<f[i]<<endl;
    }
    cout<<f[1];
}

标签:24,ch,ma,NOI,mb,int,tr,模拟,fo
来源: https://www.cnblogs.com/hzoi-fengwu/p/16372022.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有