2020牛客寒假算法基础集训营3 B 牛牛的DRB迷宫II
B 牛牛的DRB迷宫II
输入:
25
输出:
5 5
RBBBR
BBBBB
BBBDB
BDBBB
RBBBB
题解
由图求方案数,我们可以用DP求出来。但是由方案数构造图,怎么做呢?在做A题DP时我们就能体会到,这个图的构造(看题解知道的 )。一般这种构造题,我们都可以往二进制方向上想,因为二进制可以构造任何数!
官方题解不是很懂就看了这位大佬的题解报告:https://blog.csdn.net/weixin_43890662/article/details/104226161
我们可以构造一个二进制编码器,斜对角线上的方案数恰好是1,2,3,4,8,16,32…,用二进制可以拼出所有的数字,所以一定能造的出来。(引用官方题解)
题解的图是这样的,即主对角线上的格子都为B,它的上一个点为D,下一个点为R,其余我们都初始化为R。那么一开始这样的初始图的方案数为2n-1个。
那么我们输入的k怎么可能一定就是2的整数次方呢?
比如65?
我们既然是一个二进制编码器,先写出65的二进制表示为:1000001
我们可以直接用初始图表示64(1000000),那么那个‘1’就是我们要另外表示的。这条路径怎么怎加呢?
64:
-》65:
增加一条这样的路径(第1列向下,到n行后向右),即组成k的二进制数的某位出现"1"就给该位增加一条这样的路径,就相当于把k的二进制数写出来了,故叫:“二进制编码器”
现在给出AC代码:(0特判不要忘了,有详细注释)
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
const ll mod=1e9+7;
int book[35];//判断k的哪位数是1
char e[55][55];
int main(void)
{
ll k;
scanf("%lld",&k);
k%=mod;
int s=k;
int n=0;
while(k)
{
n++;
if(k&1)
book[n]=1;
k>>=1;
}//二进制可以构成任何数
//2^n<=k;
n++;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
if(i==j)
{
e[i][j]='B';
}
else if(j==i+1&&j<n)
e[i][j]='D';
else
e[i][j]='R';
}//构造最初的二进制图即对角线为B,上一个为D,下一个为R,其余全为R的图
for(int i=n;i>=1;i--){
if(book[i]==1)
{
e[i+1][i]='B';//由R变为B,因为要向下
for(int j=i+2;j<=n;j++)
e[j][i]='D';//向下
for(int j=i;j<=n;j++)
e[n][j]='R';//向右
}//当前位为1,要增加路,实际增加的路数为2^i条
}
//输出:
if(s==0)//特判 不要忘了
{
printf("%d %d\n",2,2);
printf("RR\nRR\n");
return 0;
}
printf("%d %d\n",n,n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
printf("%c",e[i][j]);
printf("\n");
}
return 0;
}