题意:给定长度,然后从26个字母中选择n个来组成一个长为n的字符串,按照字典序标号为0,1,2.......,然后题目会给你字符串,求这个字符串的标号

题解:从m个字母中选择k个组成序列的放法数位P(m,k),从左往右依次填充,进行到第i个字母时,字典序小于该字母的元素还有cnt个,则说明它前面还有cnt个P(m,k),然后扫一遍出答案,由于n<=26,所以要高精度。

View Code
 1 import java.util.*;
 2 import java.math.*;
 3 class Main
 4 {
 5     public static void main(String arg[])
 6     {
 7         Scanner cin=new Scanner(System.in);
 8         BigInteger f[][]=new BigInteger[30][30];
 9         BigInteger b[]=new BigInteger[30];
10         b[0]=BigInteger.ONE;
11         for(int i=1;i<=26;i++)
12             b[i]=b[i-1].multiply(BigInteger.valueOf(i));
13         f[0][0]=BigInteger.ONE;
14         for(int i=1;i<=26;i++)
15         {
16             f[i][0]=BigInteger.ONE;
17             for(int j=1;j<=i;j++)
18                 f[i][j]=b[i].divide(b[i-j]);
19         }
20         while(true)
21         {
22             int n=cin.nextInt();
23             if(n==0)
24                 break;
25             String tp=cin.next();
26             char s[]=tp.toCharArray();
27             boolean mark[]=new boolean[30];
28             Arrays.fill(mark, false);
29             BigInteger ans=BigInteger.ZERO;
30             for(int i=0,cnt,j,k;i<n;i++)
31             {
32                 cnt=0;
33                 k=s[i]-'A';
34                 mark[k]=true;
35                 for(j=0;j<k;j++)
36                 {
37                     if(!mark[j])
38                         cnt++;
39                 }
40                 ans=ans.add(f[26-i-1][n-i-1].multiply(BigInteger.valueOf(cnt)));
41             }
42             System.out.println(ans);
43         }
44     }
45 }