/* 写在前头,是普通SE学生,记性不太好,写过的题容易忘,记录一下*/
题面:
单点时限: 2.0 sec
内存限制: 256 MB
考虑一个 N 位的二进制串 b1…bN,其对应的二进制矩阵为:
然后将这个矩阵的行按照字典顺序排序,‘0’ 在 ‘1’ 之前。
你的任务是编写一个程序,给定排序后的矩阵的最后一列,求出已排序的矩阵的第一行。
例如:考虑二进制串(00110),排序后的矩阵为:
0 0 0 1 1
0 0 1 1 0
0 1 1 0 0
1 0 0 0 1
1 1 0 0 0
则该矩阵的最后一列为(1 0 0 1 0)。给出了这一列,你的程序应该确定第一行为(0 0 0 1 1)。
输入格式
输入第一行包含一个整数 N(0<=20000),表示二进制串的位数。第二行包含 N 个整数,表示已排序的矩阵的最后一列(从上到下)。
输出格式
输出文件仅一行,包含 N 个整数,从左到右依次表示已排序的矩阵的第一行;若无解,则输出-1。
样例
input |
---|
5 1 0 0 1 0 |
output |
0 0 0 1 1 |
思路
首先我们可以明确一点,在这个矩阵里每一列的0和1的个数相同。
给出的数据是排序好的矩阵的最后一列,所以我们可以得出将所有行数据右移一位之后各行数据所对应的新位置。
以题目给的样例来说,每一列共有3个0和2个1,所以前三行的第一位必然是0,后两行第一位是1,右移后的新顺序即为0、1的顺序。
第一行左移后就会变成第二行(第1个0出现的行),以此类推,第二行变第三行,第三行变第五行,第四行变第一行,第五行变第四行,因为这是左移后得到的顺序,所以原顺序的最后一个元素即为新顺序的倒数第二个元素。
画个简图:
所以,我们只需要用两个数组储存原顺序和新顺序,然后一步步往前推,最后输出第一行即可。
ac代码
#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
#define maxn 20001
int main(int argc, char** argv)
{
int zero,one,total,n,cnt=0;
char input[maxn],*p;
int temp[maxn],next[maxn];
cin >> n;
cin.get();
p=input;
zero=one=total=0;
char ch;
while(cin.get(ch))
{
if(ch=='0'||ch=='1')
{
*p=ch;
p++;
}
}
p=input;
while(*p)
{
if(*p=='0')
{
next[zero++]=total;
cnt++;
}
else if(*p=='1')
temp[one++]=total;
total++;
p++;
}
int i,j;
for(i=0;i<one;i++)
{
next[zero++]=temp[i];
}
char output[maxn];
for(i=j=0;i<total;i++)
{
output[i]=input[next[j]];
j=next[j];
if(output[i]=='0')
cnt--;
}
if(cnt)
{
cout << -1;
return 0;
}
for(i=0;i<total;i++)
{
cout << output[i] << " ";
}
return 0;
}