[HDU 1502][动态规划]Regular Words

来源:互联网 发布:mac配置jenkins 编辑:程序博客网 时间:2024/06/06 19:39

题目描述:
题目链接: HDU 1502

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
2

3
Sample Output
5

42
题目大意: 有A,B,C三种字母,每个字母有n0<n<=60个,求由这些字母组成的字母串有多少个满足条件:对于字母串的任意前缀,A的个数大于等于B的个数,B的个数大于等于C的个数。
注意 :输入之间中间空一行,输出中间也要空一行。
题目分析:
这道动态规划题的转移方程并不难想,我们可以令f[i][j][k]记录个数,i代表A的个数,j代表B的个数,k代表C的个数,只要保证i>=j>=k。那么转移方程就是f[i][j][k]=f[i-1][j][k]+f[i][j-1][k]+f[i][j][k-1](如果在方程中i-1<k等也没有关系,因为未更新过它,所以值就是0,并不会影响答案)。
但这道题的关键就在于,最后计算出来的答案到n=60时会非常大(八十几位),于是可以用类似于高精度的方法(压位)处理。对于f数组再开一维,f[i][j][k][p],答案这样记录,f[i][j][k][p+1]=f[i][j][k][p]/10000,f[i][j][k][p]%=10000。也就是说f数组记录的是答案每四位的值,p代表是第几个四位。
附代码:

#include<iomanip>#include<cmath>#include<ctime>#include<cstring>#include<string>#include<cstdlib>#include<cstdio>#include<cctype>#include<iomanip>#include<algorithm>using namespace std;const int INF=1e4;int n,f[65][65][65][30];void add(int a[],int b[]){    for(int i=0;i<=29;i++)    {        a[i]+=b[i];        a[i+1]+=a[i]/INF;        a[i]%=INF;    }}int main(){    //freopen("lx.in","r",stdin);    f[0][0][0][0]=1;    for(int i=1;i<=60;i++)            for(int j=0;j<=i;j++)                for(int k=0;k<=j;k++)                {                    add(f[i][j][k],f[i-1][j][k]);                    if(j-1>=k) add(f[i][j][k],f[i][j-1][k]);                    if(k-1>=0) add(f[i][j][k],f[i][j][k-1]);                }    while(scanf("%d",&n)!=EOF)    {        int k=29;        while(f[n][n][n][k]==0) k--;//找到最高位        for(int i=k;i>=0;i--)        {            if(i!=k)            {                int x=INF/10;                while(f[n][n][n][i]<x&&x>0)//对于非最高位,存在需要填充0的情况                {                    printf("0");                    x/=10;                }                if(f[n][n][n][i]!=0)printf("%d",f[n][n][n][i]);            }            else printf("%d",f[n][n][n][k]);        }        printf("\n\n");    }    return 0;}
原创粉丝点击