zoukankan      html  css  js  c++  java
  • dp+分类讨论 Gym 101128E

    题目链接:http://codeforces.com/gym/101128

    感觉这个人写的不错的(我只看了题目大意):http://blog.csdn.net/v5zsq/article/details/61428924

    Description 
    n个小木条,一段前面有一个小箭头,给出第一个小木条的非箭头端端点横坐标以及每个小木条箭头端的坐标,现在要从下往上把这n’个木条按顺序叠放好,要求相邻两个小木条必须有一个共同端点且有交叠部分,问小木条有多少种放法 
    Input 
    第一行一整数n表示木条数量,之后输入n+1个整数分别表示第一个小木条非箭头端点和n个小木条的箭头端点横坐标(1<=n < 2000,每个端点横坐标是一个介于1~n+1之间的整数,保证第一个小箭头朝右) 

    思路:

    定义dp(i,j)表示目前是第i个木头,他的区间是[min(j, a[i]), max(j, a[i])].

    然后我们判断一下a[i-1]的范围和这个区间的范围,即分类讨论五种。

    然后为了维护其中两种,所以我们这里还用了一个sum[j]数组表示dp[i][0]~dp[i][j]的和,然后这样就可以O(1)的到了

    注意特判n=1的时候(因为这个wa了一发)

    复杂度O(n^2)

    //看看会不会爆int!数组会不会少了一维!
    //取物问题一定要小心先手胜利的条件
    #include <bits/stdc++.h>
    using namespace std;
    #pragma comment(linker,"/STACK:102400000,102400000")
    #define LL long long
    #define ALL(a) a.begin(), a.end()
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    #define haha printf("haha
    ")
    const int maxn = 2000 + 5;
    const LL mod = 2147483647;
    LL dp[maxn][maxn];
    LL sum[maxn];
    int a[maxn];
    int n;
    
    int main(){
        while(scanf("%d", &n) == 1){
            for (int i = 0; i <= n; i++){
                scanf("%d", a + i);
            }
            if (n == 1) {
                printf("1
    "); continue;
            }
            memset(dp, 0, sizeof(dp));
            memset(sum, 0, sizeof(sum));
            for (int i = 1; i <= n + 1; i++){
                if (i == a[0] || i == a[1]) sum[i] = dp[1][i] = 1;
                sum[i] = 1;
            }
            int len = n + 1;
            for (int i = 2; i <= n; i++){
                for (int j = 1; j <= len; j++){
                    if (j == a[i]) continue;
                    int lb = min(j, a[i]), rb = max(j, a[i]);
                    //printf("lb = %d rb = %d
    ", lb, rb);
                    if (a[i - 1] < lb){
                        dp[i][j] += dp[i - 1][rb];
                    }
                    else if (a[i - 1] == lb){
                        dp[i][j] += (sum[len] - sum[lb] + mod) % mod;
                    }
                    else if (a[i - 1] > rb){
                        dp[i][j] += dp[i - 1][lb];
                    }
                    else if (a[i - 1] == rb){
                        dp[i][j] += sum[rb - 1];
                    }
                    else {
                        dp[i][j] += dp[i - 1][lb] + dp[i - 1][rb];
                    }
                    if (dp[i][j] >= mod) dp[i][j] %= mod;
                    //printf("dp[%d][%d] = %lld
    ", i, j, dp[i][j]);
                }
                for (int j = 1; j <= len; j++){
                    sum[j] = (sum[j - 1] + dp[i][j]) % mod;
                }
            }
            LL ans = 0;
            for (int i = 1; i <= len; i++){
                ans = (ans + dp[n][i]) % mod;
            }
            cout << ans << endl;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    【引用】将WINNT.XPE安装到移动硬盘的方法
    手把手教你把Vim改装成一个IDE编程环境(图文)(转)
    [转载]经验丰富的程序员和代码行数
    pkgconfig的使用(转)
    焦点新闻总结
    仿百度弹出框在框架页面中的应用
    发现不明确的匹配的原因和解决办法
    总结一个DAL中写IList返回实体的方法
    后台管理系统界面和样式,点击左边新建标签效果
    在用户控件中用户登录后台脚本判断
  • 原文地址:https://www.cnblogs.com/heimao5027/p/6731165.html
Copyright © 2011-2022 走看看