B. K-th Beautiful String
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
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.
The input contains one or more test cases.
The first line contains one integer t (1≤t≤104) — the number of test cases in the test. Then t test cases follow.
Each test case is written on the the separate line containing two integers n and k (3≤n≤105,1≤k≤min(2⋅109,n⋅(n−1)2).
The sum of values n over all test cases in the test doesn’t exceed 105.
For each test case print the k-th string from the list of all described above strings of length n. Strings in the list are sorted lexicographically (alphabetically).
Input
7
5 1
5 2
5 8
5 10
3 1
3 2
20 100
Output
aaabb
aabab
baaba
bbaaa
abb
bab
aaaaabaaaaabaaaaaaaa
题意:长度为n的字符串,其中由2个b,和n-2个a组成,按照顺序可以有[n*(n-1)]/2个排序,他们是按照一定顺序进行排序的,输出第k个字符串
思路:我刚开始看它字符串的规律是按照字典序的方法排序的,所以我最先使用了优先队列的办法,但是被T了,因为2⋅109太大了,之后借鉴一个大佬的,找规律,哎,思维还是太菜了,先确定倒数第二个b的位置,再去确定倒数第一个b的位置,
倒数第二个b的位置你倒着看就是从倒数第二个开始,后面到结尾有几个位置就有几种情况,把情况算成前缀和,来判断k值属于哪个区间中,然后确定了倒数第二个b的位置,再去确定倒数第一个b的位置
aaabb sum[2]=1;k=4;
aabab sum[3]=1+2=3
aabba
abaab sum[4]=3+3=6 break; j=i;k=k-sum[j-1]
ababa 4-sum[3]=4-3=1
abbaa s[n-j+1]=s[2] s[n-k+1]]=s[5]
baaab sum[5]=6+4
baaba
babaa
bbaaa
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const int N=1e5+9;
ll sum[N];
char ch[N];
int main ()
{
int n,k,t;
scanf("%d",&t);
for(int i=2;i<=100009;i++){
sum[i]=sum[i-1]+i-1;//前缀和数组,因为是倒数第2个b是从倒数第二位开始算的,
//所以,sum[i]就代表倒数第2个b是倒数第几个
//sum[i-1]+i-1,因为每加一次就加i-1个,因为i是从2开始的,而第一种情况只有1种
}
for(int g=1;g<=t;g++){
int j;
scanf("%d %d",&n,&k);
for(int i=2;i<=n;i++){
if(sum[i]>=k){
j=i;//如果前缀和数组大于等于了k,就代表在当前这个区间中
break;
}
}
k=k-sum[j-1];//k要减去之前的数量,来确定倒数第一个b所在的位置
for(int i=1;i<=n;i++){
ch[i]='a';
}
ch[n-j+1]='b';//倒数第二个b,是倒数第几个
ch[n-k+1]='b';//倒数第一个b,是倒数第几个
for(int i=1;i<=n;i++){
printf("%c",ch[i]);//输出就行
}
cout<<endl;
}
return 0;
}