• [BZOJ] 2431 逆序对数列


    Time Limit: 5 Sec  Memory Limit: 128 MB
    Submit: 2611  Solved: 1526
    [Submit][Status][Discuss]
    Description
    对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数。若对于任意一个由1~n自然数组成的
    数列,可以很容易求出有多少个逆序对数。那么逆序对数为k的这样自然数数列到底有多少个?
    Input
    第一行为两个整数n,k。
    
    Output
    写入一个整数,表示符合条件的数列个数,由于这个数可能很大,你只需输出该数对10000求余数后的结果。
    
    Sample Input
    4 1
    Sample Output
    3
    
    
    
    样例说明:
    
    下列3个数列逆序对数都为1;分别是1 2 4 3 ;1 3 2 4 ;2 1 3 4;
    
    100%的数据  n<=1000,k<=1000
    HINT
    Source
    Day1

    先想到区间dp,发现只记录前缀就行,所以二维就可以解决。
    f[i][j],前i个数,j个逆序对的方案数。
    对于新加入的i+1,可以造成i+1种逆序对,所以枚举前面的就行了。

    先写的暴力版本,TLE两个点,一算10000*1000没爆int,把mod放外面,快了不少,过了一个点,然后循环展开,不开o2也跑得飞快(相较朴素暴力…)

    #include<iostream>
    #include<cstdio>
    
    using namespace std;
    
    int n,k;
    
    int f[1005][1005]={1};
    
    int main(){
        scanf("%d%d",&n,&k);
        for(register int i=1;i<=n;i++){
            for(register int j=0;j<=k;j++){
                int l=0;
                for(l=0;l<i-8;l+=8){    
                    if(j<l) continue;
                    f[i][j]+=f[i-1][j-l];
                    if(j<l+1) continue;
                    f[i][j]+=f[i-1][j-l-1];
                    if(j<l+2) continue;
                    f[i][j]+=f[i-1][j-l-2];
                    if(j<l+3) continue;
                    f[i][j]+=f[i-1][j-l-3];
                    if(j<l+4) continue;
                    f[i][j]+=f[i-1][j-l-4];
                    if(j<l+5) continue;
                    f[i][j]+=f[i-1][j-l-5];
                    if(j<l+6) continue;
                    f[i][j]+=f[i-1][j-l-6];
                    if(j<l+7) continue;
                    f[i][j]+=f[i-1][j-l-7];
                }
                for(l;l<i;l++){
                    if(j<l) continue;
                    f[i][j]+=f[i-1][j-l];
                }
                f[i][j]%=10000;
            }
        }
        printf("%d",f[n][k]);
        return 0;
    }
    

    正解是前缀和优化,每次更新都是加一段连续区间的值,可以用前缀和降复杂度。

    #include<iostream>
    #include<cstdio>
    
    using namespace std;
    
    const int MAXN=1005;
    const int MOD=10000;
    
    int dp[MAXN][MAXN];
    int n,k,ans,sum;
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) dp[i][0]=1;
        for(int i=2;i<=n;i++)
        {
            sum=0;
            for(int j=0;j<=k;j++)
            {
                (sum+=dp[i-1][j])%MOD;
                dp[i][j]=sum%MOD;
                if(j-i+1>=0)((sum-=dp[i-1][j-i+1])+=MOD)%MOD;
            }
        }
        printf("%d
    ",dp[n][k]);
        return 0;
    }

    本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9247408.html

  • 相关阅读:
    扩展中国剩余定理
    bzoj 3816&&uoj #41. [清华集训2014]矩阵变换
    THUSC2017
    bzoj 4521: [Cqoi2016]手机号码
    bzoj 4871: [Shoi2017]摧毁“树状图”
    bzoj 2300 : [HAOI2011]防线修建
    bzoj 3853 : GCD Array
    HEOI 2017 游记
    bzoj3926: [Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机模板
    bzoj 4310 跳蚤
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9247408.html
Copyright © 2020-2023  润新知