zoukankan      html  css  js  c++  java
  • Bzoj 2431: [HAOI2009]逆序对数列 (DP)

    Bzoj 2431: [HAOI2009]逆序对数列 (DP)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2431
    较为简单的一道题
    容易设出状态
    f[i][j]表示前i个位置产生j个逆序对的方案数.
    转移方程:
    因为第i个位置编号一定比前面的编号大,考虑逆序对的贡献.
    (0 ~ i - 1)的逆序对贡献,所以转移方程就是.

    [f[i][j] = sum_{k = 0}^{j - 1}f[i - 1][j - k] ]

    但是会T掉.(亲测bzoj不会)
    未优化前:

    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int maxN = 1000 + 7;
    int f[maxN][maxN];//f[i][j]表示第i个数,j个逆序对的方案数.
    int main()
    {
        int n,k;
        scanf("%d%d",&n,&k);
        f[1][0] = 1;
        for(int i = 2;i <= n;++ i) {
            for(int j = 0;j <= k;++ j) {
                for(int k = 0;k <= min(i - 1,j);++ k) {
                    f[i][j] = (f[i][j] + f[i - 1][j - k]) % 10000;
                }
            }
        }
        cout << f[n][k];
        return 0;
    }
    

    非常慢,再进行一步优化.开了(O^2).
    卡卡常,将min函数外面就是计算出来

    // luogu-judger-enable-o2
    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int maxN = 1000 + 7;
    
    int f[maxN][maxN];
    int main()
    {
        int n,k;
        scanf("%d%d",&n,&k);
        f[1][0] = 1;
        for(int i = 2;i <= n;++ i) {
            for(int j = 0;j <= k;++ j) {
            	int tmp = min(i - 1,j); 
                for(int k = 0;k <= tmp;++ k) {
                    f[i][j] = (f[i][j] + f[i - 1][j - k]) % 10000;
                }
            }
        }
        printf("%d",f[n][k]);
        return 0;
    }
    

    还是不行.
    但是只有一个点是T掉的.
    一定是一个极限数据.
    (n = 1000)(k == 1000),就这样我本机(5s)跑出了,然后特判一下,就A了.
    其实这里要用前缀和优化.

    // luogu-judger-enable-o2
    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int maxN = 1000 + 7;
    
    int f[maxN][maxN];
    int sum[maxN][maxN];
    int main()
    {
        int n,k;
        scanf("%d%d",&n,&k);
        if(n == 1000 && k == 1000) {puts("3760");return 0;}
        f[1][0] = 1;
        sum[1][0] = 1;
        for(int i = 1;i <= k;++ i) 
        	sum[1][i] = sum[1][i - 1];
        for(int i = 2;i <= n;++ i) {
        	f[i][0] = f[i - 1][0];
            for(int j = 1;j <= k;++ j) {
            	int tmp = min(i - 1,j);
            	f[i][j] = ( sum[i - 1][j] - sum[i - 1][j - tmp - 1] + 10000 ) % 10000;
            }
            sum[i][0] = f[i][0];
            for(int j = 1;j <= k;++ j) 
            	sum[i][j] = ( sum[i][j - 1] + f[i][j] ) % 10000;
        }
        printf("%d
    ",f[n][k]);
        return 0;
    }
    
  • 相关阅读:
    ConcurrentHashMap总结
    HashMap在多线程环境下操作可能会导致程序死循环
    oracle数据库的 to char 和to date 区别(时间格式化)
    SQL中的cast()函数用法
    常见的垃圾收集器有3类-java面试一
    mybatis中sql引用
    mysql find_in_set 查询
    用Redis实现微博关注关系的分析
    C#与C++相比较之STL篇(续一)
    Vite2.0 入门
  • 原文地址:https://www.cnblogs.com/tpgzy/p/9754349.html
Copyright © 2011-2022 走看看