zoukankan      html  css  js  c++  java
  • 2017-2018 ACM-ICPC, NEERC, Moscow Subregional Contest B

    B - Byteland Trip

    题目大意:给你一个由'<' 和 '>'组成的串, 如果在'<' 只能前往编号比它小的任意点, 反之只能前往比它大的任意点,问你能遍历所有点

    并且每个点只走一次终点在各个位置的方案数。

    思路:感觉这种右能从左边跑到右边又跑回来的dp很难搞,如果我们确定一个终点, 如果知道它左边点一共出来几次,右边的点一共出来几次

    那么方案数就很好求了, 所以我们定义dp1[ i ][ j ] 表示前 i 个点,遍历所有点并且向右出去 j 次的的方案数, dp2[ i ][ j ]就是反过来的。

    对于每个点,我们枚举左边出来几次就好啦。

    #include<bits/stdc++.h>
    #define LL long long
    #define fi first
    #define se second
    #define mk make_pair
    #define PII pair<int, int>
    #define PLI pair<LL, int>
    #define ull unsigned long long
    using namespace std;
    
    const int N = 5007;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 1e9 + 7;
    const double eps = 1e-8;
    
    int n, m;
    LL dp1[N][N], dp2[N][N], f[N], ans[N];
    char s[N];
    
    void add(LL &a, LL b) {
        a += b; if(a >= mod) a -= mod;
    }
    
    int main() {
        for(int i=f[0]=1; i < N; i++) f[i] = f[i-1]*i%mod;
        scanf("%s", s + 1);
        m = strlen(s + 1);
        for(int i = 1; i <= m; i++)
            if(s[i] == '<' || s[i] == '>') s[++n] = s[i];
        if(n == 1) {
            puts("1");
            return 0;
        }
        dp1[0][0] = 1;
        for(int i = 1; i <= n; i++) {
            for(int j = 0; j <= i; j++) {
                if(s[i] == '<') {
                    add(dp1[i][j], dp1[i-1][j]*j%mod);
                    add(dp1[i][j], dp1[i-1][j+1]*(j+1)%mod*j%mod);
                } else {
                    if(j) add(dp1[i][j], dp1[i-1][j-1]);
                    add(dp1[i][j], dp1[i-1][j]*j%mod);
                }
            }
        }
        dp2[n+1][0] = 1;
        for(int i = n; i >= 1; i--) {
            for(int j = 0; j <= n-i+1; j++) {
                if(s[i] == '<') {
                    if(j) add(dp2[i][j], dp2[i+1][j-1]);
                    add(dp2[i][j], dp2[i+1][j]*j%mod);
                } else {
                    add(dp2[i][j], dp2[i+1][j]*j%mod);
                    add(dp2[i][j], dp2[i+1][j+1]*(j+1)%mod*j%mod);
                }
            }
        }
        ans[1] = dp2[2][1];
        ans[n] = dp1[n-1][1];
        for(int i = 2; i < n; i++) {
            for(int j = 1; j < i; j++) {
                add(ans[i], dp1[i-1][j]*dp2[i+1][j]%mod*f[j]%mod*f[j]%mod*2%mod);
                add(ans[i], dp1[i-1][j]*dp2[i+1][j+1]%mod*f[j]%mod*f[j+1]%mod);
                if(j > 1) add(ans[i], dp1[i-1][j]*dp2[i+1][j-1]%mod*f[j]%mod*f[j-1]%mod);
            }
        }
        for(int i = 1; i <= n; i++) printf("%lld ", ans[i]);
        return 0;
    }
    
    /*
    */
  • 相关阅读:
    第二阶段冲刺04
    找水王
    第二阶段冲刺03
    第二阶段冲刺02
    第二阶段冲刺01
    学习进度12
    梦断代码阅读笔记07
    第一阶段意见评论
    学习进度11
    求素数p的原根
  • 原文地址:https://www.cnblogs.com/CJLHY/p/9911639.html
Copyright © 2011-2022 走看看