zoukankan      html  css  js  c++  java
  • Codeforces 314 E. Sereja and Squares

    http://codeforces.com/contest/314/problem/E

    题意:

    原本有一个合法的括号序列

    擦去了所有的右括号和部分左括号

    问有多少种填括号的方式使他仍然是合法的括号序列

    括号有25种,序列长度<=1e5

    传统的做法:

    令dp[i][j]表示当前到第i个字符,现在还有j个左括号
    若第i+1个字符是左括号,则能转移到dp[i+1][j+1]
    若第i+1个字符是问号,则能转移到dp[i+1][j-1]与dp[i+1][j+1]
    时间复杂度为O(n^2)
     
    换种思路
    再看这道题,他与传统的括号序列的不同之处是他擦去了所有的右括号
    令dp[k][i]表示 假设括号只有一种,前k个里面,填了i个右括号的方案数
    如果第i个是问号
    若当前可以填左括号 dp[k][i]+=dp[k-1][i]
    若当前可以填右括号 dp[k][i]+=dp[k-1][i-1]
    dp[n][n/2]就是如果只有一种括号,使序列合法的方案数
    现在有25种括号,假设序列中已有q个左括号
    那么最终答案=25^(n/2-q) * dp[n][n/2]
     
    这个感觉上去也是n^2的
    首先把第一维压去,解决空间问题
    考虑j的枚举范围
    前i个里面,至多有i/2 [下取整] 个右括号
    至多可以填m个左括号,所以至少有i-n/2个右括号
    平摊复杂度我就不知道了
     
    对2^32取模相当于unsigned int 自然溢出
     
    然后就过了,跑的还很快
    #include<cstdio>
    
    using namespace std;
    
    #define N 100002
    
    char s[N];
    
    unsigned int f[N<<1];
    
    int main()
    {
        int n;
        scanf("%d",&n);
        if(n&1) 
        {
            putchar('0');
            return 0;
        }
        scanf("%s",s+1);
        int m=n>>1,q=0;
        f[0]=1;
        for(int i=1;i<=n;++i)
            if(s[i]=='?')
                for(int j=i>>1;j && j>=i-m;--j) f[j]+=f[j-1];
            else q++;
        unsigned int ans=f[m];
        for(int i=1;i<=m-q;++i) ans*=25;
        printf("%u",ans);
    }    
  • 相关阅读:
    python中将汉字转换成拼音
    关于拉格朗日和内维尔插值算法的python实现
    hdoj1874 (优先队列+Dijkstra)
    hdoj1325 Is It A Tree?
    poj2299 二分思想
    nyoj89 汉诺塔(二)
    nyoj914Yougth的最大化(二分搜索 + 贪心)
    nyoj832 合并游戏(状态压缩DP)
    zoj2432 hdoj1423 最长公共上升子序列(LCIS)
    poj1308 Is It A Tree?(并查集)详解
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8443668.html
Copyright © 2011-2022 走看看