高效解决 2.K-th string (微软2014在线笔试,第二题)
2014-04-13 21:15
447 查看
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的话,代码应该也比较好改)
附:第一次发博客,转载注明啊~
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"); }
相关文章推荐
- 大端和小端(Big endian and Little endian)
- Debian7 下nfs的安装和配置
- 第二周作业
- Ubuntu配置hadoop的eclipse开发环境
- OpenCV编程->OpenMP优化入门
- Spring 出现Java.Lang.ClassNotFoundException: Org.Springframework.Transaction.TransactionException
- 杭电 2047阿牛的EOF牛肉串
- OpenCV编程->OpenMP优化入门
- 使用matlab进行频谱分析时若干问题解释
- MySQL Replication需要注意的问题
- 【monkeyrunner】
- wget 非递归下载
- nyoj 308 Substring
- Eclipse中配置的Tomcat无法访问
- 说不出SDK和IDE区别?进来吧兄弟
- HTML笔记——HTML 样式
- IOS 学习笔记(4) 控件 标签(UILabel)的使用方法
- android布局属性详解
- 计算几何概览
- jquery 初步了解