noip模拟58[我拉了]

noip模拟58 solutions

主要是我心情不好,所以导致我考的非常完蛋。

做了两个题之后发现啥也不会,所以我就不想做了。

所以我只有70pts,惨死了,改题也不是很顺利。。。。

T1 lesson5

气死我了呜呜呜呜

考试上来就觉得这个题非常的操蛋

\(TMD\)是有向图,我上来就按着无向图手摸样例,然后我就直接弃掉这个题了

所以,一定要看题,仔细看,一个字也不能落下

有向图的话,直接正反分别拓扑一遍

得到从起点的最长路,到终点的最长路,这个暴力的话就可以直接枚举最长路上的点一个一个删

不过这个正解就直接把线段树干上去了

首先我们知道对于每一条边,他的贡献都是\(dis_u+dis_v+1\)于是我们可以在线段树上维护这个东西

但是你发现维护的时候,你无法将这条边的所有贡献都删掉,比如说对后面的贡献

这个时候拓扑序就有了极其重要的作用

我们先把反着走的\(dis\)插入到线段树上,这样我们就有了最大的距离,因为一定有一个点是最大距离的起点

我们按照正着走的拓扑序枚举所有的点,

每到达一个点,我们就将它反着走的\(dis\)在线段树上删除,插入正着走的\(dis\)

并且我们还要将它所有的连边,也按照上面的,插入正着的,删除反着的

这样我们在保证最长路存在的情况下,使你当前删除的点的影响被消除

AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=1e5+5;
const int M=5e5+5;
int T,n,m;
struct EDGE{
    int to[M],nxt[M],head[N],rp;
    int rd[N],xu[N],dis[N];
    void add_edg(int x,int y){
        to[++rp]=y;rd[y]++;
        nxt[rp]=head[x];
        head[x]=rp;
    }
    queue<int> q;
    void topu(){
        fo(i,1,n)if(!rd[i])xu[++xu[0]]=i,q.push(i);
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=nxt[i]){
                int y=to[i];dis[y]=max(dis[y],dis[x]+1);rd[y]--;
                if(!rd[y])xu[++xu[0]]=y,q.push(y);
            }
        }
    }
    void init(){
        memset(head,0,sizeof(head));rp=0;
        memset(rd,0,sizeof(rd));xu[0]=0;
        memset(dis,0,sizeof(dis));
    }
}one,two;
struct XDS{
    #define ls x<<1
    #define rs x<<1|1
    int sum[M*4],siz[M*4];
    void pushup(int x){
        sum[x]=max(sum[ls],sum[rs]);
        return ;
    }
    void ins(int x,int l,int r,int pos,int v){
        if(l==r){
            siz[x]+=v;
            if(siz[x]>0)sum[x]=l;
            else sum[x]=-1;
            return ;
        }
        int mid=l+r>>1;
        if(pos<=mid)ins(ls,l,mid,pos,v);
        else ins(rs,mid+1,r,pos,v);
        pushup(x);return ;
    }
    void init(){
        memset(sum,0,sizeof(sum));
        memset(siz,0,sizeof(siz));
    }
    #undef ls
    #undef rs
}xds;
int ans1,ans2;
signed main(){
    #ifdef oj
        freopen("johnny.in","r",stdin);
        freopen("johnny.out","w",stdout);
    #endif
    scanf("%d",&T);
    while(T--){
        xds.init();
        one.init();
        two.init();
        ans1=1e9;ans2=1e9;
        scanf("%d%d",&n,&m);
        fo(i,1,m){
            int x,y;scanf("%d%d",&x,&y);
            one.add_edg(x,y);two.add_edg(y,x);
        }
        one.topu();two.topu();
        fo(i,1,n)xds.ins(1,0,n,two.dis[i],1);
        fo(x,1,n){
            int now=one.xu[x];
            for(int i=two.head[now];i;i=two.nxt[i]){
                int y=two.to[i];
                xds.ins(1,0,n,two.dis[now]+one.dis[y]+1,-1);
            }
            xds.ins(1,0,n,two.dis[now],-1);
            if(xds.sum[1]<ans2||(xds.sum[1]==ans2&&now<ans1))ans1=now,ans2=xds.sum[1];
            for(int i=one.head[now];i;i=one.nxt[i]){
                int y=one.to[i];
                xds.ins(1,0,n,one.dis[now]+two.dis[y]+1,1);
            }
            xds.ins(1,0,n,one.dis[now],1);
        }
        printf("%d %d\n",ans1,ans2);
    }
}

T2 贝尔数

就这个其实对于前50pts,这就是送分的

但是后面的就有点难了

你发现这个模数根本就不是一个质数

并且你后面的那个模数转移式完全可以用矩阵快速幂优化

所以你对于每一个质数得到一个同余方程

最后用中国剩余定理合并一下就好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=55;
const int mod=95041567;
int T,n,c[N][N],bel[N],p;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int sum[10]={0,31,37,41,43,47};
int ans[10];
struct matrix{
    int a[N][N];
    matrix(){memset(a,0,sizeof(a));}
    matrix operator * (matrix x)const{
        matrix ret;
        fo(i,0,50)fo(j,0,50)fo(k,0,50)ret.a[i][j]=(ret.a[i][j]+a[i][k]*x.a[k][j])%p;
        return ret;
    }
}xs,ls;
matrix ksm(matrix x,int y){
    matrix ret;
    fo(i,0,50)ret.a[i][i]=1;
    while(y){
        if(y&1)ret=ret*x;
        x=x*x;y>>=1;
    }return ret;
}
int exgcd(int a,int b,int &x,int &y){
    if(!b)return x=1,y=0,a;
    int ret=exgcd(b,a%b,x,y);
    int tmp=x;x=y;y=tmp-y*(a/b);
    return ret;
}
signed main(){
    #ifdef oj
        freopen("bell.in","r",stdin);
        freopen("bell.out","w",stdout);
    #endif
    fo(i,0,50){
        c[i][0]=c[i][i]=1;
        fo(j,1,i-1)c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
    }
    bel[0]=1;fo(i,1,50)fo(j,0,i-1)bel[i]=(bel[i]+c[i-1][j]*bel[j])%mod;
    fo(i,1,50)xs.a[i-1][i]=xs.a[i][i]=1;
    scanf("%lld",&T);
    while(T--){
        scanf("%lld",&n);int res=0;
        if(n<=50){printf("%lld\n",bel[n]);continue;}
        fo(i,1,5){
            if(i>1)xs.a[sum[i-1]-1][0]=0;xs.a[sum[i]-1][0]=1;
            fo(j,0,50)ls.a[0][j]=bel[j]%sum[i];
            //fo(j,0,50){fo(k,0,50)cout<<xs.a[j][k]<<" ";cout<<endl;}cout<<endl;
            int tmp=n/(sum[i]-1),ys=n%(sum[i]-1);p=sum[i];
            matrix now=ls*ksm(xs,tmp);
            ans[i]=now.a[0][ys];
            //cout<<ans[i]<<endl<<endl;
            int m=mod/sum[i],x,y;
            exgcd(m,sum[i],x,y);
            x=(x%sum[i]+sum[i])%sum[i];
            res=(res+ans[i]*m%mod*x%mod)%mod;
        }
        xs.a[sum[5]-1][0]=0;
        printf("%lld\n",res);
    }
}

T3 穿越广场

所以这就是我水过AC自动机专题的后果????

我是真的不会AC自动机了

现在有一点点思路了,主要是继承其fail节点的信息

一会再去刷两道题就都会了

这个就是对两个串建立自动机,节点信息就是保存当前的节点可以包含那些子串

就直接做就好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=205;
const int mod=1e9+7;
int yg[N],an,T,n,m,ans;
char a[N];
struct ACauto{
    int tr[N][2],seg,fail[N];
    int sta[N],dp[N][N/2][N][4];
    void ins(int id){
        int now=0;
        fo(i,1,an){
            if(!tr[now][yg[a[i]-'A']])tr[now][yg[a[i]-'A']]=++seg;
            //cout<<tr[now][yg[a[i]-'A']]<<endl;
            now=tr[now][yg[a[i]-'A']];
        }
        sta[now]=id;
    }
    void build(){
        queue<int> q;while(!q.empty())q.pop();
        fo(i,0,1)if(tr[0][i])q.push(tr[0][i]);
        while(!q.empty()){
            int x=q.front();q.pop();
            //cout<<x<<endl;
            fo(i,0,1){
                if(tr[x][i]){
                    fail[tr[x][i]]=tr[fail[x]][i];
                    sta[tr[x][i]]|=sta[tr[fail[x]][i]];
                    q.push(tr[x][i]);
                }
                else tr[x][i]=tr[fail[x]][i];
            }
        }
    }
    void get_ans(){
        dp[0][0][0][0]=1;
        fo(i,0,n+m){
            fo(j,0,n){
                fo(k,0,seg){
                    fo(s,0,3){
                        int e1=tr[k][0],e2=tr[k][1];
                        (dp[i+1][j+1][e1][s|sta[e1]]+=dp[i][j][k][s])%=mod;
                        (dp[i+1][j][e2][s|sta[e2]]+=dp[i][j][k][s])%=mod;
                    }
                }
            }
        }
        fo(i,0,seg)ans=(ans+dp[n+m][n][i][3])%mod;
    }
    void clear(){
        memset(tr,0,sizeof(tr));seg=0;
        memset(dp,0,sizeof(dp));
        memset(fail,0,sizeof(fail));
        memset(sta,0,sizeof(sta));
    }
}ac;
signed main(){
    freopen("square.in","r",stdin);
    freopen("square.out","w",stdout);
    scanf("%lld",&T);yg['D'-'A']=0;yg['R'-'A']=1;
    while(T--){
        ac.clear();ans=0;
        scanf("%lld%lld",&m,&n);
        scanf("%s",a+1);an=strlen(a+1);ac.ins(1);
        scanf("%s",a+1);an=strlen(a+1);ac.ins(2);
        ac.build();ac.get_ans();
        printf("%lld\n",ans);
    }
}

T4 舞动的夜晚

这个其实可以直接暴力网络流,删一个点再跑一遍

但是正解是\(网络流+tarjan\)

直接在网络流的残量网络上跑\(tarjan\)

如果一条边的两个点在同一个联通分量里或者在最大流上,这个就是可以的

AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=200005;
const int M=1000005;
const int inf=0x3f3f3f3f;
int n,m,T;
int fu[M],tu[M];
int fr[M*2],to[M*2],nxt[M*2],val[M*2],id[M*2],head[N],hea[N],rp=1;
void add_edg(int x,int y,int z,int i){
    to[++rp]=y;
    fr[rp]=x;id[rp]=i;
    val[rp]=z;
    nxt[rp]=head[x];
    head[x]=rp;
}
int s=20001,t=20002,ans,ji[M];
int dep[N];
bool bfs(){
    memcpy(head,hea,sizeof(head));
    memset(dep,0x3f,sizeof(dep));
    queue<int> q;while(!q.empty())q.pop();
    q.push(s);dep[s]=0;
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=nxt[i]){
            int y=to[i];
            if(!val[i]||dep[y]<=dep[x]+1)continue;
            q.push(y);dep[y]=dep[x]+1;
            if(y==t)return true;
        }
    }
    return false;
}
int dfs(int x,int in){
    if(x==t)return in;
    int rst=in,go;
    for(int i=head[x];i;head[x]=i=nxt[i]){
        int y=to[i];
        if(!val[i]||dep[y]!=dep[x]+1)continue;
        go=dfs(y,min(val[i],rst));
        if(go)rst-=go,val[i]-=go,val[i^1]+=go;
        else dep[y]=0;
        if(!rst)break;
    }return in-rst;
}
void dinic(){
    memcpy(hea,head,sizeof(hea));
    int ret=0;
    while(bfs())ret+=dfs(s,inf);
}
int dfn[N],low[N],cnt,bel[N],tot;
stack<int> sta;
void tarjan(int x){
    dfn[x]=low[x]=++cnt;
    sta.push(x);
    for(int i=head[x];i;i=nxt[i]){
        int y=to[i];
        if(!dfn[y])tarjan(y),low[x]=min(low[x],low[y]);
        else if(!bel[y])low[x]=min(low[x],low[y]);
    }
    if(dfn[x]==low[x]){
        bel[x]=++tot;
        while(x!=sta.top())bel[sta.top()]=tot,sta.pop();
        sta.pop();
    }
}
bool vis[M];
signed main(){
    #ifdef oj
        freopen("night.in","r",stdin);
        freopen("night.out","w",stdout);
    #endif
    scanf("%d%d%d",&n,&m,&T);
    fo(i,1,T){
        scanf("%d%d",&fu[i],&tu[i]);tu[i]+=n;
        add_edg(fu[i],tu[i],1,0);
        add_edg(tu[i],fu[i],0,i);
    }
    fo(i,1,n)add_edg(s,i,1,0),add_edg(i,s,0,0);
    fo(i,1,m)add_edg(i+n,t,1,0),add_edg(t,i+n,0,0);
    dinic();
    int nn=rp;memset(head,0,sizeof(head));rp=1;
    fo(i,1,nn)if(val[i])add_edg(fr[i],to[i],1,id[i]),vis[id[i]]=true;//cout<<fr[i]<<" "<<to[i]<<endl;
    fo(i,1,n+m)if(!dfn[i])tarjan(i);//cout<<i<<" ";cout<<endl;
    fo(i,1,T)if(bel[fu[i]]!=bel[tu[i]]&&!vis[i])ji[++ans]=i;
    //fo(i,1,n+m)cout<<i<<" "<<bel[i]<<endl;
    printf("%d\n",ans);
    fo(i,1,ans)printf("%d ",ji[i]);
}
posted @ 2021-09-24 07:18  fengwu2005  阅读(34)  评论(0编辑  收藏  举报