题意
多组数据。每次把n张纸叠在一起,然后把左边翻折到右边,一共翻折k次。再从上往下往纸头上写数字,正反面都写。写完后把纸头展平,一张张纸从上到下从左到右地输出其上的数字。 n , k ( 1 ≤ n ≤ 200 , 1 ≤ k ≤ 10 ) n, k(1≤n≤200,1≤k≤10) n,k(1≤n≤200,1≤k≤10)
题解
分析发现其实每次翻折回去的操作就是把上半部分倒过来(旋转180度),然后把下半部分拼到原来上半部分的右边去。直接模拟需要的空间太大。
又发现在一叠纸的同一位置的数字串是不会分开的,只有正着和倒着的区别,所以用vector把每个位置的2n个数存储起来,用rev数组表示是正序还是倒序,然后对位置序号模拟就可以,只需要
2
k
∗
2
k
2^k*2^k
2k∗2k的数组,大概1000000,可以接受。
代码
#include<iostream>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
//mxn=2^k
const int mxn=1050;
bool s=0;
int a[2][mxn][mxn];
int n,m,c,k;
vector<int> v[mxn];
//rev=0 顺序输出 =1则逆序输出
bool rev[mxn];
//虚假的快速幂,无关紧要
int ksm(int a,int b)
{
int ret=1;
for(int i=0;i<b;i++)
ret*=a;
return ret;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&k);
m=ksm(2,k);
c=1;
memset(rev,0,sizeof(rev));
s=0;
for(int i=1;i<=m;i++) a[0][i][1]=i;
for(int i=1;i<=m;i++)
{
v[i].clear();
for(int j=0;j<n*2;j++)
{
int tmp;
scanf("%d",&tmp);
v[i].push_back(tmp);
}
}
while(m!=1)
{
for(int j=1;j<=c;j++)
{
for(int i=1;i<=m/2;i++)
{
a[s^1][m/2+1-i][c+1-j]=a[s][i][j];
rev[a[s][i][j]]^=1;
}
}
for(int i=m/2+1;i<=m;i++)
{
for(int j=1;j<=c;j++)
{
a[s^1][i-m/2][c+j]=a[s][i][j];
}
}
m/=2;
c*=2;
s^=1;
}
bool start=1;
for(int i=0;i<n*2;i++)
{
for(int j=1;j<=c;j++)
{
if(start) start=0;
else printf(" ");
int no=a[s][1][j];
printf("%d",v[no][rev[no]==0?i:n*2-1-i]);
}
}
printf("\n");
}
return 0;
}