【线性DP】——hdu1502——渐进推理+大数
Regular Words
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1982 Accepted Submission(s): 765
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
题意:
给你A,B,C三种字母,问你,
当有n个A,n个B,n个C的时候,满足组成的字符串的所有前缀A的个数大于等于B的个数大于等于C的个数,并B的个数大于等于C的个数有多少个?
思路:
这道题的dp有点难想,从题目的字面上理解: 当i=1时, ans= ABC 当i=2时, ans= AABBCC AABCBC ABABCC ABACBC ABCABC 其实不难发现,若集合ans中的任一子串的前缀满足A(C)>=B(C)>=C(C)那么一定有第一个B前面必有A,第一个C前面必有B,第二个B前面必有两个A,第二个C前面必有两个B………………
不难推出,当i=n时的所有满足要求的串为i=n-1的所有满足要求的子串中在任意位置插入'A','B','C',A必插入在B之前,B必插入在C之前,
然后就是想如何在i=n-1的所有串中不重不漏地插入ABC,得出i=n的值,但这样的话好像找不到什么可以解决的方法。。。 那么我们可不可以不一下子地从ans1={ABC}跳到ans2={AABBCC,AABCBC,ABABCC....},
先从{ABC}跳到{ABCA,ABCB,ABCC}这样行不行?那么就从加入ABC的问题变为加入A或B或C的问题了,
就相当于求i=n时在i=n-1上的子串结尾加入A或B或C,然后挑出最后满足要求的子串,好,AC!
转移方程是dp[i][j][k]=dp[i-1][j][k]+dp[i][j-1][k]+dp[i][j][k-1];(i>j>k)
代码如下:
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.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.valueOf(0); 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>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(); } }
题后感:
当题目给出的状态是离散的,
那么可以不考虑怎么从离散的相邻状态转移,
而可以用题目隐含的,真实存在的“过渡状态”使状态变为连续的

浙公网安备 33010602011771号