NOI模拟24


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

原题,不多说什么,做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];
}

原创文章,作者:kepupublish,如若转载,请注明出处:https://blog.ytso.com/267077.html

(0)
上一篇 2022年6月14日
下一篇 2022年6月14日

相关推荐

发表回复

登录后才能评论