Time Limit: 10000ms
Case Time Limit: 1000ms
Memory Limit: 256MB
Description
Consider a string set that each of them consistsof {0, 1} only. All strings in the set have the same number of 0s and 1s. Writea program to find and output the K-th string according to the dictionary order.If such a string doesn’t exist, or the input is not valid, please output“Impossible”. For example, if we have two ‘0’s and two ‘1’s, we will have a setwith 6 different strings, {0011, 0101, 0110, 1001, 1010, 1100}, and the 4thstring is 1001.
Input
The first line of the input file contains a singleinteger t (1 ≤ t ≤ 10000), the number of test cases, followed by the input datafor each test case.
Each test case is 3 integers separated by blankspace: N, M(2 <= N + M <= 33 and N , M >= 0), K(1 <= K <=1000000000). N stands for the number of ‘0’s, M stands for the number of ‘1’s,and K stands for the K-th of string in the set that needs to be printed asoutput.
Output
For each case, print exactly one line. If thestring exists, please print it, otherwise print “Impossible”.
Sample In
3
2 2 2
2 2 7
4 7 47
Sample Out
0101
Impossible
01010111011
本问题属于排序问题,寻找第K位数
对于已排好序的数组则时间复杂度为O(1)
未排好序的数组,时间复杂度为O(N)(N为数组大小)
本问题如果要得到排序,首先时间复杂度就会很高,为O(C(N,M+N))
思路很简单,就是排列组合的知识。
但是这样做复杂度太高。
采用计数的方式,计算全排列个数,则可以将时间复杂度降到O(M+N),这里假设计算排列组合的时间复杂度为O(1)(事实上,确实可以做到,只是需要使用公式)
循环:
如果减少1个0后的排序个数仍大于K,则可以在首位放一个0,组合数变为C(N-1,M+N-1);
小于K,则首位放置一个1,但是这时应该更新K,因为放置1之后,余下部分的排列数中已经减少了一部分,剩下的排列组合数只需要补足余下的个数就可以了,组合数变为C(N,M+N)。
若等于K,则退出循环,剩余的0和1只需按最大排列即可。即1在前面,0在后面。
具体减少多少呢?
减少量 = 当前组合数 – 取走1之后的组合数
K = K – 减少量
这样循环下去,只需要最多M+N次,能得到该Kth 字符串;
具体边界条件比较简单,参看代码即可。
(代码水平比较渣,凑合看吧,lz正在努力学习中。没有参加微软的笔试,所以只是实现了思路,具体OJ的话,代码应该也比较好改)
附:第一次发博客,转载注明啊~
#include <iostream>
using namespace std;
int Count(int up, int down){
if (up > down / 2)
up = down - up;
long long fenzi = 1;
long long fenmu = 1;
for (int i = 1; i <= up; ++i)
fenmu *= i;
for (int i = down - up + 1; i <= down; ++i)
fenzi *= i;
return fenzi / fenmu;
}
bool getK(int zero, int one, int K, char* res){
int up = zero;
int down = zero + one;
int C = Count(up, down);
if (C < K)
return false;
int index = 0;
while (C!=K && up < down && up > 0)
{
if (Count(up-1,down-1) >= K) {
up--;
down--;
res[index] = '0';
}
else{
down--;
K = K - (C - Count(up,down));
res[index] = '1';
}
C = Count(up, down);
index++;
}
int tmp = index - 1;
for (; index <= tmp + down - up; ++index)
res[index] = '1';
tmp = index - 1;
for (; index <= tmp + up; ++index)
res[index] = '0';
res[index + 1] = '\0';
return true;
}
int main()
{
char *res = new char[16];
if (getK(2, 2, 6, res))
cout << res << endl;
else
cout << "Impossible" << endl;
delete [] res;
system("pause");
}