NOI模拟8

沈老师如约切掉了两个题,在我啥也不会的时候eee%%%

T1考场上神奇的蒙了个构造方式就60pts了,T2看了一眼就是圆方树直接走人,T3打了暴力和部分分,一直局限在某一值域上

T1 出题人

发现可以找到一个环,然后找到一个结论,双向搜索

这里主要说一下归并的过程:

说是搜索,千万不要写搜索,因为那样的复杂度是假的,我们枚举下一个数放到哪个集合中,然后归并,这样的复杂度是对的

然而我写的时候并没有意识到这个,于是带着log,大力卡常...

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--)
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=14349000;
const int inf=1e12;
int n,m,a[35],b[35],ans1[35],ans2[35];
int pw[35],lm;
vector<int> s,t,o;
struct node{
    int first,second;
    node(){}node(int a,int b){first=a;second=b;}
    bool operator < (node a)const{
        return first<a.first;
    }
    bool operator == (node a)const{
        return first==a.first;
    }
};
vector<node> fi,se;
void dfs1(int x,int zt,int as){
    if(x==m+1)return fi[zt]=node(as,zt),void();
    dfs1(x+1,(zt<<1)+zt,as);
    dfs1(x+1,(zt<<1)+zt+1,as+a[x]);
    dfs1(x+1,(zt<<1)+zt+2,as-a[x]);
}
bool flag=false;
void dfs2(int x,int zt,int as){
    if(flag)return ;
    if(1.0*clock()/CLOCKS_PER_SEC>=1.95){printf("No");exit(0);}
    if(x==n+1){
        if(zt==0)return ;
        node now=node(as,zt);
        node ps=*lower_bound(fi.begin(),fi.end(),now);
        if(now==ps){
            fi.push_back(ps);se.push_back(now);
            flag=true;
        }
        return ;
    }
    dfs2(x+1,(zt<<1)+zt,as);
    dfs2(x+1,(zt<<1)+zt+1,as+a[x]);
    dfs2(x+1,(zt<<1)+zt+2,as-a[x]);
}
signed main(){
    freopen("problemsetter.in","r",stdin);
    freopen("problemsetter.out","w",stdout);
    n=read();m=n+1>>1;
    bool even=false;int wo;
    fo(i,1,n){
        a[i]=read();
        if(a[i]%2==0)even=true,wo=a[i];
    }
    if(even){
        printf("Yes\n");
        b[1]=wo/2;int now=1;
        fo(i,1,n){
            if(a[i]==wo)ans1[i]=ans2[i]=1;
            else ans1[i]=now,ans2[i]=++now,b[now]=a[i]-b[now-1];
        }
        fo(i,1,n)printf("%lld ",b[i]);printf("\n");
        fo(i,1,n)printf("%lld %lld\n",ans1[i],ans2[i]);
        return 0;
    }
    fo(i,1,n)a[i]+=inf;
    pw[0]=1;fo(i,1,n)pw[i]=pw[i-1]*3;
    fi.resize(pw[m]);dfs1(1,0,0);
    sort(fi.begin(),fi.end());
    for(node i:fi)if(!i.first&&i.second){
        flag=true;fi.push_back(i);se.push_back(node(0,0));break;
    }
    dfs2(m+1,0,0);
    if(!flag){printf("No");return 0;}
    cerr<<1.0*clock()/CLOCKS_PER_SEC<<endl;

    int now=fi.back().second;
    fu(i,m,1){
        if(now%3==1)s.push_back(i);
        else if(now%3==2)t.push_back(i);
        else o.push_back(i);
        now/=3;
    }
    now=se.back().second;
    fu(i,n,m+1){
        if(now%3==1)t.push_back(i);
        else if(now%3==2)s.push_back(i);
        else o.push_back(i);
        now/=3;
    }
    b[1]=0;now=1;
    while(s.size()){
        now++;b[now]=a[s.back()]-inf-b[now-1];
        ans1[s.back()]=now-1;ans2[s.back()]=now;
        s.pop_back();
        if(s.size()){
            now++;b[now]=a[t.back()]-inf-b[now-1];
            ans1[t.back()]=now-1;ans2[t.back()]=now;
            t.pop_back();
        }
    }
    ans1[t.back()]=1;ans2[t.back()]=now;
    for(int i:o)b[++now]=a[i]-inf,ans1[i]=1,ans2[i]=now;
    printf("Yes\n");
    fo(i,1,n)printf("%lld ",b[i]);printf("\n");
    fo(i,1,n)printf("%lld %lld\n",ans1[i],ans2[i]);
}

T2 彩色挂饰

这,圆方树题了,先缩了

设f[x][c]表示x点颜色是c的最小次数,这是圆点的定义

方点则表示他爹的颜色是c的最小次数

圆点可以直接转移,方点的话可以枚举相连的每个圆点的个数,再做一个小dp,转移就行了

这代码里的圆方树是错的...

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--)
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=2e5+5;
const int inf=0x3f3f3f3f;
int n,m,k,ss,co[N];
vector<int> d[N],e[N];
int dfn[N],low[N],cnt;
int sta[N],top;
bool fd[N];
void tarjan(int x){
    dfn[x]=low[x]=++cnt;
    sta[++top]=x;
    for(int y:d[x]){
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
            if(low[y]==dfn[x]){
                n++;fd[n]=true;
                while(sta[top]!=x){
                    e[sta[top]].push_back(n);
                    e[n].push_back(sta[top]);
                    top--;
                }
                e[x].push_back(n);e[n].push_back(x);
            }
        }
        else low[x]=min(low[x],dfn[y]);
    }
}
int dp[N][25],zy[1<<7][25],zg[1<<7],hh[1<<7];
int ys[7],cys,pp[7];
bool lt[1<<7];int in[N];
void dfs_dp(int x,int f){
    fo(c,1,k)dp[x][c]=1;
    for(int y:e[x])if(y!=f)dfs_dp(y,x);
    if(fd[x]){
        // cerr<<x<<endl;
        cys=0;for(int y:e[x])ys[++cys]=y,in[y]=cys,pp[cys]=0;
        for(int y:e[x]){
            for(int z:d[y])if(in[z]){
                pp[in[y]]|=1<<(in[z]-1);
            }
        }
        int u=(1<<cys)-1;
        fo(s,0,u)lt[s]=false;
        fo(i,1,cys)lt[1<<i-1]=true;
        fo(s,1,u){
            if(lt[s]){
                // cerr<<s<<" ";
                fo(i,1,cys)if((!((s>>(i-1))&1))&&(s&pp[i])){
                    lt[s|(1<<i-1)]=true;
                }
            }
            zg[s]=inf;
            fo(c,1,k){
                if(!lt[s]){
                    zy[s][c]=inf;
                    continue;
                }
                zy[s][c]=1;
                fo(i,1,cys)if((s>>(i-1))&1){
                    zy[s][c]+=dp[ys[i]][c]-1;
                }
                zg[s]=min(zg[s],zy[s][c]);
            }
        }
        // cerr<<endl;
        hh[0]=0;fo(s,1,u)hh[s]=inf;
        fo(s,0,u)for(int t=(u^s);t;t=(t-1)&(u^s)){
            hh[s|t]=min(hh[s|t],hh[s]+zg[t]);
        }
        fo(c,1,k){
            dp[x][c]=inf;
            if(co[x]&&co[x]!=c)continue;
            fo(s,0,u)if(((s>>in[f]-1)&1)){
                dp[x][c]=min(dp[x][c],zy[s][c]+hh[u^s]);
            }
        }
        for(int y:e[x])in[y]=0;
    }
    else {
        fo(c,1,k){
            if(co[x]&&co[x]!=c){
                dp[x][c]=inf;
                continue;
            }
            dp[x][c]=1;
            for(int y:e[x])if(y!=f){
                dp[x][c]+=dp[y][c]-1;
            }
        }
    }
    // cerr<<x<<"    ";
    // fo(c,1,k)cerr<<dp[x][c]<<" ";
    // cerr<<endl;
}
signed main(){
    freopen("colorful.in","r",stdin);
    freopen("colorful.out","w",stdout);
    n=read();m=read();k=read();ss=read();
    fo(i,1,n)co[i]=read();
    fo(i,1,m){
        int x=read(),y=read();
        d[x].push_back(y);d[y].push_back(x);
    }
    int nn=n;fo(i,1,nn)if(!dfn[i])tarjan(i);
    // cerr<<n<<endl;
    dfs_dp(1,0);
    int ans=inf;
    fo(c,1,k)ans=min(ans,dp[1][c]);
    printf("%lld\n",ans);
    return 0;
}

T3 逆转函数

说实话,这就是一个互相对应的回文串,所以跑马拉车

千万不要想着去记录函数的对应,而是记录位置的对应,这样的话就可以很方便的翻转过来了...

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--)
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=6e5+5;
const int mod=998244353;
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 n,m,a[N],pm[N],ans;
int nxt[N],pre[N],pos[N];
int p[N],as[N],sm[N];
signed main(){
    freopen("invfunc.in","r",stdin);
    freopen("invfunc.out","w",stdout);
    n=read();m=read();
    pm[0]=1;fo(i,1,m)pm[i]=pm[i-1]*m%mod;
    fo(i,1,n)a[i]=read();
    fu(i,n,1)a[i*2]=a[i],a[i*2+1]=0;a[1]=0;
    fo(i,0,m)pos[i]=0;
    fo(i,1,2*n+1){
        pre[i]=pos[a[i]];
        pos[a[i]]=i;
    }
    fo(i,0,m)pos[i]=2*n+2;
    fu(i,2*n+1,1){
        nxt[i]=pos[a[i]];
        pos[a[i]]=i;
    }
    // fo(i,1,2*n+1){
    //     cerr<<a[i]<<" "<<pre[i]<<" "<<nxt[i]<<endl;
    // }
    int mx=0,id;
    fo(i,1,2*n){
        if(i<mx){
            int ls=id*2-i;
            p[i]=min(p[ls],mx-i);
            sm[i]=sm[ls];as[i]=as[ls];
            fu(j,p[ls],p[i]+1){
                int l=ls-j+1,r=ls+j-1;
                if(a[l]){
                    sm[i]-=pm[as[i]];
                    as[i]+=(nxt[l]>r)+(pre[r]<=l);
                }
            }
        }
        else {
            // cerr<<i<<endl;
            p[i]=1;
            if(a[i]){
                sm[i]=pm[m-1];
                as[i]=m-1;
            }
            else sm[i]=0,as[i]=m;
        }
        int l=i-p[i],r=i+p[i];
        while(l>=1&&r<=2*n+1&&(nxt[l]>=r||a[r]==a[l+r-nxt[l]])&&(pre[r]<=l||a[l]==a[l+r-pre[r]])){
            p[i]++;
            if(a[l]){
                as[i]-=(nxt[l]>r)+(pre[r]<=l);
                sm[i]+=pm[as[i]];
            }
            l=i-p[i];r=i+p[i];
        }
        if(i+p[i]>mx)mx=i+p[i],id=i;
        // cerr<<i<<" "<<p[i]<<" "<<sm[i]<<" "<<as[i]<<endl;
    }
    fo(i,1,2*n+1)ans=(ans+sm[i])%mod;
    printf("%lld\n",ans);
}
posted @ 2022-05-15 22:06  fengwu2005  阅读(59)  评论(0编辑  收藏  举报