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 }
知世故而不世故,处江湖而远江湖,才是最成熟的善良