第k个字符串-------(思想)

第k个字符串

题目:

给定两个整数 n 和 k。
用 n−2 个 a 和 2 个 b 来构成一个字符串,则一共可以构成 n(n−1)/2个不同的字符串。
将这 n(n−1)/2 个字符串按照字典序进行排序。
请输出排好序后,排在第 k 个的字符串。
例如,当 n=5,k=2 时,共可以生成 10 个不同的字符串,按字典序排列如下:
aaabb
aabab
aabba
abaab
ababa
abbaa
baaab
baaba
babaa
bbaaa
其中,排在第 2 个的字符串为 aabab。
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据占一行,包含两个整数 n 和 k。
输出格式
每组数据输出一行结果,表示答案。
数据范围
前三个测试点满足 1≤T≤10,1≤n≤20,1≤k≤100。
所有测试点满足 1≤T≤10000,3≤n≤105,1≤k≤min(2×109,n(n−1)2)。
同一测试点内所有 n 的和不超过 105。

输入样例:
7
5 1
5 2
5 8
5 10
3 1
3 2
20 100
输出样例:
aaabb
aabab
baaba
bbaaa
abb
bab
aaaaabaaaaabaaaaaaaa

思路: k的极端值为2*10^9,一直序列数++很显然会超时,所以用全排列写肯定是不行的,转换思路找出两个‘b’的与k位置关系,成为了一道找规律题。
n=5时该字符串的的全排列
第k个字符串-------(思想)_第1张图片
由此过程可推算出b的移动规律:b1先向左移动1位,然后b2向左移动,直到到b1的后一位,然后b1再次向左移动1位,此时b2回到字符串的最后一位,然后b2再次向左移动。以此类推,每移动一格全排列的序列+1;
在b1固定时,从上至下,依次有1,2,3,4种情况,也就是1~n-1,因此可以推出b1,b2的位置

		int ans=0,b1,b2;		//ans为全排列的序列号
		for(int i=1;i<n;i++){	//既是b1从右到左的位置(从0开始),也是此时b2的情况数
			if(ans+=i>=k){		//如果ans>k,说明判断的范围超了,此时的i,就为b1的从右向左的位置
				ans-=i;			//返回到该情况的第一种
				b1=i;
				break;
			}
		}
		b2=k-ans-1;//k-ans,计算还剩下数量,因为下标从0开始,所以多减去一个1。

AC代码

#include 
using namespace std;
int p[100010];
int main()
{
	int t,n,k;
    cin>>t;
    while(t--){
        memset(p,0,sizeof(p));
        cin>>n>>k;
        int ans=0;
        for(int i=1;i<n;i++){
            if((ans+=i)>=k){
				ans-=i;
				p[i]=1;
				break;
			}
        }
        p[k-ans-1]=1;
        for(int i=n-1;i>=0;i--)		//因为是计算的是从右到左b的位置,所以输出是反着来就行了
			if(p[i]) cout<<'b';
			else cout<<'a';
        cout<<endl;
    }
    return 0;
}

你可能感兴趣的:(笔记)