题目链接:https://ac.nowcoder.com/acm/contest/3004/B
第一次写这种构造题,比赛的时候没想出来QAQ。构造方法很巧妙。先把官方题解的图拉过来。
解释一下这张图:初始状态如图,空白区域(除了最后一行)全填D,最后一行全填R。
从0开始计数,第i行第i列(即对角线元素)的值为2i(也就是1<<i)。2n之内的所有2的倍数通过各种组合的相加可以构成1到2n+1之间的所有数字。为便于理解对上图修改如下
要求res对应的方格为最终答案,只需要判定res是由哪些数字构成的和,然后将对应列的蓝色区域的R改为B即可。这样就会将当前列对应的值向下传递直到最后一行。
然后既然答案会对1e9+7取模,所以我们只需要计算30列,因为1<<30=1 073 741 824,下标0~29。
对于行数而言需要32行,因为第31行(下标30)需要对第30行(下标29)的数据进行选择是否处理。第32行(下标31)全R来将答案从左到右传递到最后一格。
对于判断由哪些数字组成的和利用二进制和位运算即可。
附代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=55; 4 char res[maxn][maxn]; 5 int main(){ 6 int n=32,m=30; 7 int k; 8 cin>>k; 9 for(int i=0;i<30;i++){ 10 res[0][i]='D'; 11 res[30][i]='D'; 12 res[31][i]='R'; 13 } 14 res[0][0]='B'; 15 res[30][29]='R'; 16 for(int i=1;i<30;i++){ 17 for(int j=0;j<i-1;j++){ 18 res[i][j]='D'; 19 } 20 res[i][i-1]='R'; 21 res[i][i]='B'; 22 for(int j=i+1;j<30;j++){ 23 res[i][j]='D'; 24 } 25 } 26 for(int i=0;i<30;i++){ 27 if(k&(1<<i))res[i+1][i]='B'; 28 } 29 cout<<n<<" "<<m<<" "; 30 for(int i=0;i<n;i++){ 31 for(int j=0;j<m;j++){ 32 cout<<res[i][j]; 33 } 34 cout<<" "; 35 } 36 return 0; 37 }