20250205 省选模拟赛 T3

20250205 省选模拟赛 T3

Description

设计一个 \(n\times n\) 的 01 矩阵,使得从 \((1,1)\) 走到 \((n,n)\) 且只能向右或下走且只经过为 \(1\) 的格子的方案数为 \(X\)

\(n \leq 24\) 时得满分。\(X \leq 10^9\)

Solution

基于 \(2\) 进制的构造方法

我们称从左上到右下的 \(2\times 2\) 的方块为 “基块”,延伸至右侧的长条为 “导线”。最右侧的导线占据了 \((1,n)\)\((n,n)\)

从一个红色方块走到右下方的红色方块,方案数为 \(2\)。从 \(0\) 从左上到右下标号,走到第 \(i\) 个方格的走法有 \(2^i\) 种。

构造方法为,如果 \(X\) 在二进制下第 \(i\) 位为 \(1\),我们就从第 \(i\) 个红色方块向右拉一条导线。

基于 \(6\) 进制的构造方法

将基块改为 \(3\times 3\),那么从基块的左上角走到右下角方案数为 \(6\)

\(6\) 进制下,如果 \(X\) 的第 \(i\) 位有值,我们就向下或向右拉一条导线。

此时需要图中蓝色和绿色的 “位块” 来处理每一位的值,对 \(1,2,3,4,5\) 分别构造。

基于 \(20\) 进制的构造方法

同上,我们将基块改为 \(4\times 4\),走完一个基块的方案数变为 \(20\)

此时我们需要 \(4 \times 5\) 的位块,它们需要满足最右侧全部为 \(1\),以接在导线上。

使用 dfs 进行枚举:

void dfs(int x,int y){
    if(!x) return Check();
    if(!y) return dfs(x-1,m);
    if(y!=m&&(!(x==1&&y==1))){
        a[x][y]=0; dfs(x,y-1);
        if(ok) return;
    }
    a[x][y]=1; dfs(x,y-1);
}

如果再像上面一样构造,\(n\) 至少为 \(25\)。考虑对最高位进行优化。

最高位的位块我们改为 \(3 \times 6\),这样可以同时利用两条导线,省掉一行一列。

由于 \(X\leq 10^9\),只需要处理 \(1\sim 15\)。它们需要满足最下方和最右方都为 \(1\)

但我们无法构造出 \(13,14\) 的位块。考虑换用 \(4\times 6\)

绿色部分为新换用的位块。为了避免与左侧位块 “粘连”,橙色区域必须为 \(0\)

int val1[23][8][8],val2[23][8][8];
int f[8][8],X,c[8];
bool ok;

void Check1(int k){
    memset(f,0,sizeof(f));
    f[0][0]=1;
    for(int i=0;i<=4;i++){
        for(int j=0;j<=3;j++){
            if(i<4&&val1[k][i+1][j]) f[i+1][j]+=f[i][j];
            if(j<3&&val1[k][i][j+1]) f[i][j+1]+=f[i][j];
        }
    }
    if(f[4][3]==k) ok=1;
}

void dfs1(int x,int y,int k){
    if(x<0) return Check1(k);
    if(y<0) return dfs1(x-1,3,k);
    if(y!=3&&(!(x==0&&y==0))){
        val1[k][x][y]=0;
        dfs1(x,y-1,k);
        if(ok) return;
    }
    val1[k][x][y]=1;
    dfs1(x,y-1,k);
}

void Check2(int k){
    memset(f,0,sizeof(f));
    f[0][0]=1;
    for(int i=0;i<=5;i++){
        for(int j=0;j<=2;j++){
            if(i<5&&val2[k][i+1][j]) f[i+1][j]+=f[i][j];
            if(j<2&&val2[k][i][j+1]) f[i][j+1]+=f[i][j];
        }
    }
    if(f[5][2]==k) ok=1;
}

void dfs2(int x,int y,int k){
    if(x<0) return Check2(k);
    if(y<0) return dfs2(x-1,2,k);
    if(y!=2&&x!=5&&(!(x==0&&y==0))){
        val2[k][x][y]=0;
        dfs2(x,y-1,k);
        if(ok) return;
    }
    val2[k][x][y]=1; dfs2(x,y-1,k);
}

void Check3(int k){
    memset(f,0,sizeof(f));
    f[0][0]=1;
    for(int i=0;i<=5;i++){
        for(int j=0;j<=3;j++){
            if(i<5&&val2[k][i+1][j]) f[i+1][j]+=f[i][j];
            if(j<3&&val2[k][i][j+1]) f[i][j+1]+=f[i][j];
        }
    }
    if(f[5][3]==k) ok=1;
}

void dfs3(int x,int y,int k){
    if(x<0) return Check3(k);
    if(y<0) return dfs3(x-1,3,k);
    if(y!=3&&x!=5&&(!(x==0&&y==0))){
        val2[k][x][y]=0;
        dfs3(x,y-1,k);
        if(ok) return;
    }
    if(!(y==0&&x<5&&x>=2)){
        val2[k][x][y]=1;
        dfs3(x,y-1,k);
        if(ok) return;
    }
}

void Init(){
    for(int i=1;i<=19;i++){
        ok=0;
        dfs1(4,3,i);
    }
    for(int i=1;i<=15;i++){
        if(i==13||i==14) continue;
        ok=0;
        dfs2(5,2,i);
        
    }
    ok=0; dfs3(5,3,13);
    ok=0; dfs3(5,3,14);
}

int ans[26][26];

signed main(){
    FileIO();
    Init();
    read(X);
    for(int i=1;i<=7;i++){
        c[i]=X%20;
        X/=20;
        // printf("C[%d]=%d\n",i,c[i]);
    }
    for(int i=1;i<=24;i++) ans[i][24]=ans[24][i]=1;
    for(int i=1,x=1;i<=6;i++,x+=3){
        for(int j=0;j<=3;j++){
            for(int k=0;k<=3;k++)
                ans[x+j][x+k]=1;
        }
    }
    for(int i=1,x=1;i<=7;i++,x+=3){
        // printf("I=%d,X=%d\n",i,x);
        if(!c[i]) continue;
        if(i%2==0){
            for(int j=x;j<=24;j++) ans[j][x]=1;
            for(int j=0;j<=3;j++){
                for(int k=0;k<=4;k++)
                    ans[24-(3-j)][x+k]=val1[c[i]][k][j];
            }
        }
        else if(i<=6){
            for(int j=x;j<=24;j++) ans[x][j]=1;
            for(int j=0;j<=4;j++){
                for(int k=0;k<=3;k++)
                    ans[x+j][24-(3-k)]=val1[c[i]][j][k];
            }
        }
        else if(c[i]==13||c[i]==14){
            for(int j=x;j<=24;j++) ans[x][j]=1;
            for(int j=0;j<=5;j++){
                for(int k=0;k<=3;k++)
                    ans[x+j][24-(3-k)]=val2[c[i]][j][k];
            }
        }
        else{
            for(int j=x;j<=24;j++) ans[x][j]=1;
            for(int j=0;j<=5;j++){
                for(int k=0;k<=2;k++)
                    ans[x+j][24-(2-k)]=val2[c[i]][j][k];
            }
        }
    }
    puts("24");
    for(int i=1;i<=24;i++){
        for(int j=1;j<=24;j++){
            putchar(ans[i][j]+'0');
            putchar(' ');
        }
        puts("");
    }
    return 0;
}
posted @ 2025-02-05 22:49  XP3301_Pipi  阅读(58)  评论(0)    收藏  举报
Title