省选模拟27

联赛后第一次rk1吧!?还挺激动的

开场发现checker是exe,人傻了,于是我就想要换windows,然而没换成因为windows没有g++

于是万能的水哥出场了,把exe转成了linux下的可执行文件!!!

第一题开场想到了根号的构造方法,最后搞到了正解

第二题看了一会就走了,这玩意实在是不可做

第三题没多久就想到了是状压dp,可以叫插头dp?写的时候细节多得很,一一直写到了11点30,那时的我认为11点50结束考试,给我紧张坏了,11点44的时候4*4的样例都过不了,于是我放弃了,花了2分钟打了个暴力就交上去了

交完之后发现woc12点10分结束!!然后继续调,揪出来两个小错误,然后就切掉了

T1 分裂

一开始想的是我每一层只拿一个下去,最后二进制拆分一下,这样是根号的

然后想一层只剩下一个,剩下的都拿下去,然后发现这样不可行

于是想到了一个折半的做法,每层拿下一半去!!哈哈哈,我可真是个天才

发现最后一层剩下的那一半可以下放两层,这样一定可以满足条件,最后二进制拆分微调就好了

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*10+ch-'0';ch=getchar();}
    return s*t;
}
const int N=1e7+5;
int T,n,buc[30],gx[30],all[30],ans[30];
signed main(){
    freopen("split.in","r",stdin);
    freopen("split.out","w",stdout);
    int now=1;
    gx[1]=1;all[1]=1;
    fo(i,2,25){
        all[i]=all[i-1]-(now+1>>1);
        buc[i-1]=(now>>1);
        now=((now+1)>>1)*i;
        gx[i]=now;
        all[i]+=gx[i];
    }
    T=read();
    while(T--){
        n=read();
        if(n==1){printf("1\n1 1\n");continue;}
        if(n==3||n==5||n==8){printf("-1\n");continue;}
        memset(ans,0,sizeof(ans));
        fo(nn,1,25)if(n<all[nn]){nn-=1;
            int ys=n-all[nn];
            fo(i,1,nn-1)ans[i]=buc[i];
            ans[nn]=gx[nn];ans[0]=nn;
            if(ys>ans[nn-1]*(nn-1)){
                ans[0]=nn+1;ys-=ans[nn-1]*(nn-1);
                ans[nn]+=ans[nn-1]*nn;ans[nn-1]=0;
                if(ys>=nn){
                    ans[nn+1]+=ys/nn*(nn+1);ans[nn]-=ys/nn;
                    ys%=nn;
                }
            }
            else if(ys>=nn-1){
                ans[nn]+=ys/(nn-1)*nn;ans[nn-1]-=ys/(nn-1);
                ys%=(nn-1);
            }
            fu(i,ans[0],1)if(ys>=i&&ans[i]){
                ans[i]--;ans[i+1]+=i+1;
                ys-=i;ans[0]=max(ans[0],i+1);
            }
            if(ys){
                fo(i,2,ans[0]-1)if(ans[i+1]>i+1){
                    ans[i]++;ans[i+1]-=i+1;
                    ans[i+1]--;ans[i+2]+=i+2;
                    ans[0]=max(ans[0],i+2);
                    break;
                }
            }
            int res=0;
            fo(i,1,ans[0])if(ans[i])res++;
            printf("%lld\n",res);
            fo(i,1,ans[0])if(ans[i])printf("%lld %lld\n",i,ans[i]);
            break;
        }
    }
    return 0;
}

T2 未来

遇到这种题,先想想怎么能把这玩意转化成运算,因为只有算数题才能加速,并且找到可以简化的地方

于是我们给每个字符映射到0,1,2上,发现变换就是\(a_i=(a_i+a_{i+1})*2\%3\)

于是这个东西我们依旧不知道怎么做,但是发现好像一层一层的展开最后是个杨辉三角

想到组合数,发现是对3取模,lucas定理,我们每次转移三进制的某一位,就是\(3^k \choose i\),这样i只有两位是有值的0和\(3^k\)

于是有了logm的做法

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*10+ch-'0';ch=getchar();}
    return s*t;
}
const int N=5e5+5;
char ch[N];
int n,m,a[N],b[N];
signed main(){
    freopen("future.in","r",stdin);
    freopen("future.out","w",stdout);
    n=read();m=read();
    scanf("%s",ch);
    fo(i,0,n-1){
        if(ch[i]=='r')a[i]=0;
        else if(ch[i]=='g')a[i]=1;
        else a[i]=2;
    }
    while(m){
        int stp=1;
        while(stp<=m/3)stp*=3;
        while(m>=stp){
            fo(i,0,n-1)b[i]=(a[i]+a[(i+stp)%n])*2%3;
            fo(i,0,n-1)a[i]=b[i];m-=stp;
        }
    }
    fo(i,0,n-1)printf("%c",a[i]?(a[i]==2?'b':'g'):'r');
}

T3 回忆

直接状压dp,由于宽度最大是6,最多的联通块个数是3,可以4进制压位,压成12位

用map记录每一个联通块的大小,以及历史最大值,转移就行了

细节贼多!!!

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*10+ch-'0';ch=getchar();}
    return s*t;
}
const int N=41;
const int mod=998244353;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=1ll*ret*x%mod;
        x=1ll*x*x%mod;y>>=1;
    }return ret;
}
int n,m,jz[N][N],ans;
struct node{
    int a[5];
    node(){memset(a,0,sizeof(a));}node(int x,int y,int z,int w=0){a[1]=x;a[2]=y;a[3]=z;a[4]=max(w,max(a[1],max(a[2],a[3])));}
    bool operator < (node x)const{
        if(a[1]!=x.a[1])return a[1]<x.a[1];
        if(a[2]!=x.a[2])return a[2]<x.a[2];
        if(a[3]!=x.a[3])return a[3]<x.a[3];
        return a[4]<x.a[4];
    }
};
map<node,int> dp[N][1<<12];
int fai[15],bai[15],zti[15],bti[15];
int find(int x){return fai[x]==x?x:fai[x]=find(fai[x]);}
int get(int s,int i){return (s>>(i-1)*2)&3;}
int bia[15];
signed main(){
    freopen("memory.in","r",stdin);
    freopen("memory.out","w",stdout);
    n=read();m=read();
    if(n>m)fo(i,1,n)fo(j,1,m)jz[i][j]=read();
    else {
        fo(i,1,n)fo(j,1,m)jz[j][i]=read();
        swap(n,m);
    }
    dp[0][0][node(0,0,0,0)]=1;
    int u=(1<<m*2)-1;
    fo(x,1,n){
        fo(s,0,u){
            if(dp[x-1][s].size()==0)continue;
            fo(i,1,m)fai[i]=bai[i]=i,zti[i]=1<<get(s,i);
            fo(i,m+1,2*m)fai[i]=bai[i]=i,zti[i]=0;
            fo(i,1,m)fo(j,i+1,m){
                if(get(s,i)==get(s,j)){
                    int fx=find(i),fy=find(j);
                    if(fx==fy)continue;
                    fai[fy]=fx;zti[fy]|=zti[fx];
                }
            }
            fo(i,1,2*m)bai[i]=fai[i],bti[i]=zti[i];
            for(pair<node,int> o:dp[x-1][s]){
                if(!o.second)continue;
                fo(t,0,(1<<m)-1){
                    fo(i,1,2*m)fai[i]=bai[i],zti[i]=bti[i],bia[i]=0;
                    int las=0,num=0,ss=0;node res=node(0,0,0,o.first.a[4]);
                    fo(i,1,m+1)if(!((t>>i-1)&1)){
                        if(las+1>i-1){las=i;continue;}
                        fo(j,las+1,i-1){
                            if(!get(s,j))continue;
                            int fx=find(j+m),fy=find(j);
                            if(fx==fy)continue;
                            fai[fx]=fy;zti[fy]|=zti[fx];
                        }
                        fo(j,las+1,i-2){
                            int fx=find(j+m),fy=find(j+m+1);
                            if(fx==fy)continue;
                            fai[fx]=fy;zti[fy]|=zti[fx];
                        }las=i;
                    }
                    fo(i,1,m){
                        if(!((t>>i-1)&1))continue;
                        if(!bia[find(i+m)]){
                            bia[find(i+m)]=++num;
                            fo(j,1,3)if((zti[find(i+m)]>>j)&1){
                                res.a[bia[find(i+m)]]+=o.first.a[j];
                            }
                        }
                        ss|=(1<<(i-1)*2)*bia[find(i+m)];
                        res.a[bia[find(i+m)]]++;
                    }
                    res.a[4]=max(res.a[4],max(res.a[1],max(res.a[2],res.a[3])));
                    int gl=1;
                    fo(i,1,m){
                        if((t>>i-1)&1)gl=1ll*gl*jz[x][i]%mod;
                        else gl=1ll*gl*(mod+1-jz[x][i])%mod;
                    }
                    if(!gl)continue;
                    dp[x][ss][node(res)]=(dp[x][ss][node(res)]+1ll*o.second*gl%mod)%mod;
                }
            }
        }
    }
    fo(s,0,u){
        for(pair<node,int> o:dp[n][s]){
            int mx=o.first.a[4];
            ans=(ans+1ll*mx*o.second%mod)%mod;
        }
    }
    printf("%lld",ans);
    return 0;
}
posted @ 2022-03-07 15:35  fengwu2005  阅读(49)  评论(0编辑  收藏  举报