Regular Words
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Problem Description
Consider words of length 3n over alphabet {A, B, C} . Denote the number of occurences of A in a word a as A(a) , analogously let the number of occurences of B be denoted as B(a), and the number of occurenced of C as C(a) .
Let us call the word w regular if the following conditions are satisfied:
A(w)=B(w)=C(w) ;
if c is a prefix of w , then A(c)>= B(c) >= C(c) .
For example, if n = 2 there are 5 regular words: AABBCC , AABCBC , ABABCC , ABACBC and ABCABC .
Regular words in some sense generalize regular brackets sequences (if we consider two-letter alphabet and put similar conditions on regular words, they represent regular brackets sequences).
Given n , find the number of regular words.
Let us call the word w regular if the following conditions are satisfied:
A(w)=B(w)=C(w) ;
if c is a prefix of w , then A(c)>= B(c) >= C(c) .
For example, if n = 2 there are 5 regular words: AABBCC , AABCBC , ABABCC , ABACBC and ABCABC .
Regular words in some sense generalize regular brackets sequences (if we consider two-letter alphabet and put similar conditions on regular words, they represent regular brackets sequences).
Given n , find the number of regular words.
Input
There are mutiple cases in the input file.
Each case contains n (0 <= n <= 60 ).
There is an empty line after each case.
Each case contains n (0 <= n <= 60 ).
There is an empty line after each case.
Output
Output the number of regular words of length 3n .
There should be am empty line after each case.
There should be am empty line after each case.
Sample Input
2 3
Sample Output
5 42
————————————————————————————————————————————————————————
题意:给你三个字符ABC,设字符串中ABC的个数相等,再给你每个字符的个数,问在下列条件下,能形成几种排列:前i个字符中,n(A) >= n(B) >= n(C)。即A的个数大于等于B的个数大于等于C的个数。
思路:如果按照排列组合的思路的确不容易。但是如果是dp的话,首先状态就很容易表示:
dp[i][j][k]代表当前A的个数、B的个数、C的个数。
先看dp[1][1][1]的构造过程:(若要保证构造的过程合法,就必须先填A再填B最后填C)
dp[0][0][0] -> dp[1][0][0] -> dp[1][1][0] -> dp[1][1][1]
再来看dp[2][2][2]的过程:(红色代表填A,蓝色填B,绿色填C)
易见,只要满足填字符之前以及填字符之后i >= j >= k,就可以填。
状态转移方程只要能满足这个条件就可以。
P.S. 由于排列数过多long long溢出,就用Java写了
Java代码如下:
import java.util.*;
import java.math.*;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
BigInteger dp[][][] = new BigInteger[61][61][61];
dp[0][0][0] = BigInteger.ONE;
//dp[0][0][0] = BigInteger.valueOf(1);
for(int i = 1; i <= 60; i++) {
for(int j = 0; j <= i; j++) {
for(int k = 0; k <= j; k++) {
dp[i][j][k] = BigInteger.ZERO;
if(i-1 >= j)
dp[i][j][k] = dp[i][j][k].add(dp[i-1][j][k]);
if(j-1 >= k)
dp[i][j][k] = dp[i][j][k].add(dp[i][j-1][k]);
if(k-1 >= 0)
dp[i][j][k] = dp[i][j][k].add(dp[i][j][k-1]);
}
}
}
while(cin.hasNext()) {
int n = cin.nextInt();
System.out.println(dp[n][n][n]);
System.out.println();
}
cin.close();
}
}