zoukankan      html  css  js  c++  java
  • HDU6880 Permutation Counting 【思维+dp】

    题目链接
    题目描述
    存在长度为n的排列,给定一个长度(n - 1)的排列满足以下两种情况
    1、(a_i>a_{i-1}, b[i] = 1)
    2、(a_i < a_{i_1}, b[i] = 0)
    现在给一个长度为(n-1)的b序列,问有多少种排列满足条件
    思路
    比赛时没有想到,赛后看了题解。
    构造方法:初始状态下存在一个1,若b[i]==1,那么2就放在1的左边,否则2就放在1的右边,依次推类。
    以样例1 0为例,先放一个1,b[1]=1,此时序列就变成了2 1, b[2]=0,那么3就放在2的右边,有以下两种情况, 2 3 1 / 2 1 3. 这样构成的序列叫一个p序列的话,那么就表示第(i)个数字应当放在第(p_i)位,所以排列种类数就等价于求构成这种p序列的方案数。
    dp[i][j]表示数字(i)在第(j)位的所有方案数。
    那么若b[i]=1,dp[i][j] = (sum_{k=j+1}^{k=i}dp[i-1][k])
    若b[i]=0,dp[i][j] = (sum_{k=1}^{k=j-1}dp[i-1][k])
    但是此时是(O(n^3))的复杂度,直接跑会TLE,可以通过一个sum的初始将复杂度降到(O(n^2))
    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef pair<int, int> PII;
    const int INF = 0x3f3f3f3f;
    const int MOD = 1e9 + 7;
    const int N = 5010;
    LL dp[N][N];
    int b[N];
    
    void solve() {
        int n; scanf("%d", &n);
        for(int i = 2; i <= n; i++) {
            scanf("%d", &b[i]);
        }
        memset(dp, 0, sizeof dp);
        dp[1][1] = 1;
        for(int i = 2; i <= n; i++) {
            LL sum = 0;
            if(b[i]) {
                for(int j = 1; j <= i; j++) {
                    sum = (sum + dp[i - 1][j]) % MOD;
                }
                for(int j = 1; j <= i; j++) {
                    dp[i][j] = (dp[i][j] + sum) % MOD;
                    sum = (sum - dp[i - 1][j] + MOD) % MOD;
                    // for(int k = j; k <= i; k++) {
                    //     dp[i][j] = (dp[i][j] + dp[i - 1][k]) % MOD;
                    // }
                }
            } else {
                for(int j = 1; j <= i; j++) {
                    dp[i][j] = (dp[i][j] + sum) % MOD;
                    sum = (sum + dp[i - 1][j]) % MOD;
                    // for(int k = 1; k <= j - 1; k++) {
                    //     dp[i][j] = (dp[i][j] + dp[i - 1][k]) % MOD;
                    // }
                }
            }
        }
        LL res = 0;
        for(int i = 1; i <= n; i++) {
            res = (res + dp[n][i]) % MOD;
        }
        printf("%lld
    ", res);
    }
    
    int main() {
        // freopen("in.txt", "r", stdin);
        int t; cin >> t; while(t--)
        solve();
        return 0;
    }
    
    
  • 相关阅读:
    HTML5 Canvas 颜色填充学习
    PHP中使用函数array_merge()合并数组
    div border-radius
    php中数组可以不写下标
    ab apache Benchmarking中链接的写法 记得加上/
    div border-radius画圆
    Why should i use url.openStream instead of of url.getContent?
    Using Java SecurityManager to grant/deny access to system functions
    In Java, what is the default location for newly created files?
    三种纯CSS实现三角形的方法
  • 原文地址:https://www.cnblogs.com/ZX-GO/p/13559526.html
Copyright © 2011-2022 走看看