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;
    }
    
  • 相关阅读:
    火狐中,设置align="center"失效的解决方法
    爱学习的你,不知道这五个神奇网站怎么行
    详解Linux运维工具:运维流程管理、运维发布变更、运维监控告警
    运维工程师必备技能:网络排错思路讲解
    非常全的Linux基础知识点
    Linux系统CPU占用率较高问题排查思路
    MySQL数据库参数优化
    Linux查看硬件配置
    JumpServer堡垒机安装笔记
    nginx的安装和负载均衡例子(RHEL/CentOS7.4)
  • 原文地址:https://www.cnblogs.com/tpgzy/p/9754349.html
Copyright © 2011-2022 走看看