TJU_2146_Computer DJ

来源:互联网 发布:现代软件学院学费 编辑:程序博客网 时间:2024/06/08 17:43
2146.   Computer DJ
Time Limit: 5.0 Seconds   Memory Limit:65536K
Total Runs: 554   Accepted Runs:178



A very famous DJ has been recently invited to play in the closing party of a Computer Scienceconference. Trying to impress the participants of the event, he decided to use a program inorder to choose the songs he would play at this party. However, the result was a disaster, sincethe way the program chose the songs was quite weird and repetitive.

First of all, the DJ has selected N songs among the set of songs he had available. Theprogram used by the DJ then labels each of the songs using one different character from 'A'to 'Z'. Theith song is labeled using theith character of the sequence 'A'-'Z'. The programchooses the songs to be played in the party in the order that their labels appear in the followinginfinite sequence of characters: first come all the words with one character in lexicographicalorder; then all the words with two characters in lexicographical order; then all the words withthree characters in lexicographical order; and so on. ForN = 3, this sequence would beABCAAABACBABBBCCACBCCAAAAABAACABAABBABC...

At the end of the party, some people asked the DJ if he remembered which the first songplayed was. Others would like to know which the 25th was, and so on. The DJ remembersnothing but the strange pattern of repetition of the songs, so he urges you to help him andwrite a program which answers such queries.

Input

The input contains several test cases. Each test case consists of three lines. The first line of atest case contains two integersN andQ indicating respectively the number of songs chosen bythe DJ and the number of queries made by the participants (1 ≤N ≤ 26 and 1 ≤Q ≤ 1000).In the second line, there will be theN titles of the songs (the title of a song is a chain ofalphanumerical characters of at least one and at most 100 characters) separated by singlespaces. The last line of a test case contains a sequence of queries. Each query is a numberk(1 ≤k ≤ 100000000) corresponding to thekth song played in the party. The end of the inputis indicated byN =Q = 0.

Output

For each query number k in a test case, you shall print a single line containing the name of thekth song played in the party. A blank line must follow each test case.

Sample input

10 3S0 S1 S2 S3 S4 S5 S6 S7 S8 S93 6 103 5Pathethique TurkishMarch Winter1 2 3 4 160 0

Output for the sample input

S2S5S9PathethiqueTurkishMarchWinterPathethiqueWinter


Source: South America 2005


题意:有N首歌,N最多26,所以可以分别用大写字母A-Z来标记,DJ播放音乐的顺序很有意思,它按N首歌长度为1,2,3,……的排列的字典序来播放,对于N=3时,分别用ABC来代替每首歌:

长度为1时:ABC

长度为2时:AA AB AC,BA BB BC,CA CB CC

长度为3时:AAA AAB AAC ABA ABB ABC ACA ACB ACC,BAA BAB BAC BBA BBB BBC BCA BCB BCC,CAA CAB CAC CBA CBB CBC CCA CCB CCC

……

把这些长度为1,2,3……的所有排列串起来,问第k个字母是什么?这个字母就代表某首歌。

可以看出长度为1的串有N^1个,长度为2的有N^2个,长度为3的有N^3个,……,它们对应的长度区间为,[1,N],[N+1,N+2*N^2],[N+2*N^2+1,N+2*N^2+3*N^3],……这样写出来反而不直观了。实际上就是一个累加而已,长度为1的排列的长度有1*N,长度为2的排列的长度有2*N^2,长度为3的排列长度有3*N^3,长度为L的排列长度有L*N^L,这些长度的累加就是我们要查询的位置K。

如果有个K,通过如下算法,我们至少知道它落在长度为多少的排列的区间:

p=N;

len=1;

while(K>p*len)

 {

      k-=p*len;

     p*=N;

     len++;

}

len就表面长度为几的排列。

举个例子说明一下,取N=3,K=3;

p*len=3,while()不会执行,所以K=3落在排列长度为1的区间。

取N=3,K=9;

len++会执行一次,K-p*len=6,接下来p=9,len=2,将不会执行while()循环体,所以9落在排列长度为2的区间。

对于余数K=6,因为长度为2的排列形式是首先是A占用6,再B占用6,然后是C占用6,合起来长度为18,所以用6/6=1,我们就知道第一个字母一定是A,如果是7/6得到1(这时原始的K=10),这时还要加1,即余数不为0时要加1,因为7是落在B开头的排列里。再接着考虑6怎么处理,6-2*3^1=0,这时说明6刚好覆盖以A开头的全排列AAABAC,那要播放的那首歌一定是C。而对于7来说7-2*3^1=1,我们还要继续搜索它的第二个字母是什么。因为第二个字母是一个字母的排列组成的,我们再用1和2*3^0作比较,连一个长度为2的排列都组合不出来了,这个字母肯定就是B了。

K最后一定是落在长度为len的某个排列里,对于N=3,比如1,2,3都在长度为1的排列里,4到21都是落在长度为2的排列里,22到102都是落在长度为3的排列里;而长度为3的排列是由长度为2的排列在前面加上一个字母来得到的,在长度为3的排列里,前面3*3^2是以A开头的,中间3*3^2是以B开头的,后面的3*3^2是以C开头的;长度为2的排列是由长度为1的排列在前面加上一个字母得到的,在长度为3的排列里的前面3*3^2个字母里,前面3*3^1第二个字母是A,中间3*3^1第二个字母是B,后面3*3^1第二个字母是C;长度为1的排列是由3个字母排列得到的,在长度为3的排列里前面3*3^1个字母里,前面3*3^0字母的第三个字母为A,中间3*3^0个字母的第三个字母是B,后面3*3^0的第三个字母是C。通过上面的规律,我们可以进一步确定了K所在这个排列的每个字母,那也就清楚K这个字母是什么了。仔细看下这个图:


好像有点越说越糊涂的感觉,总体来说就是两步:

(1)确定K落在长度为几的排列,假设是len

(2)确定K所在的这个排列的每个字母,K所在这个排列长度为1至len


#include<stdio.h>#include<string.h>int n,q;//n=歌的数量,q=询问次数char music[29][105];//每首歌的名字int play[100];//保存某次询问K所在排列的每个字母int main(){    int i,p,len,k,m;    while(1)    {        scanf("%d%d",&n,&q);        if(0==n&&0==q)break;        for(i=1;i<=n;i++);//输入每首歌的名字            scanf("%s",&music[i]);        for(i=1;i<=q;i++)//处理q次询问        {            scanf("%d",&k);//每次询问的位置为k            if(1==n);//如果一共只有一首歌,不关k取多少都是同一首歌,这里不特殊处理的话play[]数组会溢出            {                printf("%s\n",music[1]);//输出,继续处理下一次询问                continue;            }            p=n;//p记录n的方幂            len=1;//表示落在长度为几的排列            while(k>=p*len)            {                k-=p*len;//k减去长度为len的全排列                p*=n;//p=p*n,即p上升一个幂级                len++;//k所在排列长度加1            }            //处理完上面的步骤如果k=0,那么k=N^1+2*N^2+3*N^3+..L*N^L,            //k所在的位置一定是第N个字母,比如N=3时,3,21,102都是这种情况            if(0==k)            {                printf("%s\n",music[n]);                continue;            }            //如果k不为0,k一定落在长度为len的某个排列            memset(play,0,sizeof(play)); //初始化play[]            p/=n;//p下降一个幂级,因为长度为len的排列是长度为len-1的排列推出来的            m=1;//m记录处理到了第几个字母,由前往后,m最多为len,至少为1            while(m<=len&&k>0)//m最多为len,当k=0在m<len到达意味着k是以某个全排列结束,k所在一定是第N个字母            {                if(k%(p*len)==0)//如果k%(p*len)==0,那么第m个字母是k/(p*len)                     play[m++]=k/(p*len);                else                    play[m++]=k/(p*len)+1;//如果k%(p*len)!=0,那么第m个字母是k/(p*len)+1                while(k>=p*len)//将长度为len-m的全排列的字母减去,以便确定下一个字母是什么                {                    k-=p*len;                }                p/=n;//p下降一个幂级,再去处理下一个字母            }            if(k>0)//当k%n!=0时会出现这种情况,但k所在排列的第k%n个字母已经由前面的步骤求得,可以推推N=3,k=7                play[len]=play[k];//第k个字母即为所求            else if(m<=len)//这是k==0,如果还没有处理到第len个字母,说明k结束在某个全排列的最后一个字母即N,可以推推N=3,k=9                play[len]=n;            //这个隐含处理到了第len个字母,那么答案就是前面所求,可以推推N=3,k=6            printf("%s\n",music[play[len]]);//play[len]是抽象的字母,也代表第几首歌        }        printf("\n");    }    return 0;}/*3 100Pathethique TurkishMarch Winter*/
这注释在TC上写出来的,编译不通过,可手边就只有TC,不知道会不会有错,明天再改改。

原创粉丝点击