定长最小权值字符串个数-TopCoder-SRM586-DIV2-1000pt

题目见:

http://community.topcoder.com/stat?c=problem_statement&pm=12695&rd=15698

题目大意为,给定长度为L,计算所有权值最小的字符串的个数。权值定义为所有字母出现的最右位置-最左位置的加和。

容易想到的,若L<=26,那么显然每种字母只有一个时权值为0,最小,只要有字母重复就会大于0.所以此时字符串个数为C(26,1)*C(25,1)...C(26-L+1,1)个。

若L>26。则需要仔细思考怎样的字符串能够满足最小。

1)首先容易想到,26个字母必须都用上,不然能反证替换掉重复字符使权值更小。

2)对每个字母,其出现的位置必须是连续的,如果不是连续的,可以通过调整到连续使字符串更小。

所以以上两个条件给出了这种字符串长什么样: 1)每个字符出现至少一次。2)同一字符必须连续。

由此,可以通过构造的方法对这个计数问题进行DP或MEMO。

f (p , l): 已知字符串的[p+1,n),目前还有l个字符没有出现过,则[0,p]的字符串可能数是多少?

很容易对p位上的情况进行状态转移:

1) 使用跟p+1一样的字母。 res += f(p-1, l);

2) 重新选择一个字母填入当前位置。res += f(p-1,l-1) * C(l,1)

然后注意一些边界条件即可。

int m,n;
const int MODULAR=1000000009;
class StringWeightDiv2
        { 
        public: 
            int comb[27][27];
            int dp[1001][27];
            //clac the combination use C(a,b)=C(a-1,b-1)+C(a-1,b)
            int CalcC(int n,int m){
                if (n==0 && m==0){return 1;}
                if (n==0){return 0;}
                if (m==0){return 1;}
                if (n<m){return 0;}
                if (comb[n][m]!=-1){return comb[n][m];}
                int res=(CalcC(n-1,m-1)+CalcC(n-1,m))%MODULAR;
                comb[n][m]=res;
                return res;
            }
            //how many ways for [0,p] with l charectors unused
            int Solve(int p,int l){
                if (p==-1){return l==0;}
                if (dp[p][l]!=-1){return dp[p][l];}
                long long res=0;
                if (l>0){    //begin a new consecutive seria
                    res+=(long long)Solve(p-1,l-1)*CalcC(l,1);
                    res%=MODULAR;
                }
                if (l<26){    //continue with last charactor
                    res+=Solve(p-1,l);
                    res%=MODULAR;
                }
                dp[p][l]=(int)res;
                return (int)res;
            }
        int countMinimums(int L) 
            { 
                memset(comb,-1,sizeof(comb));
                if (L<=26){        //just select unique charactors in the permutation
                    long long res=1;
                    for (int i=0;i<L;i++){
                        res*=CalcC(26-i,1);
                        res%=MODULAR;
                    }
                    return res;
                }
                else{
                    //when L>26, the string should meet:
                    //1)use all the 26 characters
                    //2)for one specify character, its appearance must be consecutive.
                    memset(dp,-1,sizeof(dp));
                    return Solve(L-1,26);
                }
            } 
};

 

转载于:https://www.cnblogs.com/yangsc/p/3988349.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值