For the given integer n (n>2) let's write down all the strings of length n which contain n−2 letters 'a' and two letters 'b' in lexicographical (alphabetical) order.

Recall that the string s of length n is lexicographically less than string t of length n, if there exists such i (1≤i≤n), that si<ti, and for any j (1≤j<i) sj=tj. The lexicographic comparison of strings is implemented by the operator < in modern programming languages.

For example, if n=5 the strings are (the order does matter):

aaabb
aabab
aabba
abaab
ababa
abbaa
baaab
baaba
babaa
bbaaa
It is easy to show that such a list of strings will contain exactly n⋅(n−1)2 strings.

You are given n (n>2) and k (1≤k≤n⋅(n−1)2). Print the k-th string from the list.

题意:长度为n的字符串,其中有2个b,n-2个a,求n个字符组成的第k小的字符串。

因为只有两个b,所以b的位置决定了字符串的大小,我们知道字典序是从前向后比较的,所以左边b对字符串的大小的影响更大。下面我们来看一下左边b的位置对字典序的影响。以aaabb为例:右边的b可以从最后一位一直挪到左边b的右边,每向前一个位置

 b:2  1

b:3   2-3

b: 4  4-6

b:  5  7-10

依次类推,我们可以发现1=2*1/2,3=3*2/2,6=4*3/2……所以当b在第x位的时候,字符串的字典序可以在(x-1)*(x-2)/2-x*(x-1)/2之间波动,而具体是多少就取决于右边的b了,k比(x-1)*(x-2)/2-1大多少,b就在第几位,所以我们预处理一下f数组,fi=i*(i-1)/2,一定要开long long!因为1e5*1e5=1e10,会超int,大概只有我这个憨憨会觉得1e10没有超int吧

前面我们说的第几位都是从后往前数的,输出的时候还要倒回来。

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const long long maxn=1e5+5;
 5 long long n,k,t;
 6 long long f[maxn];
 7 long long x,y;
 8 int main()
 9 {
10     for(long long i=1;i<maxn;++i)
11         f[i]=(i*(i-1))/2;
12     scanf("%d",&t);
13     while(t--)
14     {
15         x=2,y=1;
16         scanf("%d%d",&n,&k);
17         for(long long i=1;i<maxn;++i)
18             if(f[i]>=k)
19             {
20                 x=i;break;
21             }
22         y=k-(f[x-1]);
23         x=n-x+1,y=n-y+1;
24         for(long long i=1;i<=n;++i)
25             if(i==x||i==y)printf("b");
26             else printf("a");
27         printf("\n"); 
28     }
29     return 0;
30 }