【DP】HDU-1502 Regular Words

来源:互联网 发布:淘宝卖家说给补偿5元 编辑:程序博客网 时间:2024/06/06 01:42

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.
 

Input
There are mutiple cases in the input file. 

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.
 

Sample Input
23
 

Sample Output
542
 
————————————————————————————————————————————————————————
题意:给你三个字符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();    }}


0 0
原创粉丝点击