zoukankan      html  css  js  c++  java
  • [2016北京集训测试赛7]isn-[树状数组+dp+容斥]

    Description

     

    Solution

    定义dp[i][j]为在1到i个数中选了j个数,并且保证选了i的选法总数。

    dp[i][j]为所有满足A[k]>A[i]的k(k<i)的dp[k][j-1]之和。在处理完dp[i][j]后,在树状数组里A[i]位置填上dp[i][j-1]的值就好。这样可以优化一下复杂度。[A可能要离散化一下]

    然后,容斥大法好~

    定义g[x]为最终序列长度为x的方案数。由于x是从大变小,所有的g[i]都是已经处理完毕的了。

    (似乎还有一种不用n2操作,直接扫一遍就好的方法,不知道是不是二项式反演)

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int mod=1e9+7;
    typedef long long ll;
    int n,a[2010],t[2010],rk[2010];
    bool cmp(int x,int y){return a[x]<a[y];}
    ll dp[2010][2010],g[2010];
    
    
    ll fac[2010],inv[2010];
    void pre()
    {
        fac[0]=fac[1]=inv[0]=inv[1]=1;
        for (int i=2;i<=n;i++)
        {
            fac[i]=fac[i-1]*i%mod;
            inv[i]=(mod-mod/i)*inv[mod%i]%mod;
        }
        for (int i=2;i<=n;i++) inv[i]=inv[i]*inv[i-1]%mod;
    }
    ll C(int x,int y){return fac[y]*inv[x]%mod*inv[y-x]%mod;}
    
    
    ll tree[2010];
    void add(int id,ll x){for(;id<=n;id+=id&-id) tree[id]+=x,tree[id]%=mod;}
    ll query(int id){ll re=0;for(;id;id-=id&-id) re+=tree[id],re%=mod;return re;}
    int main()
    {
        scanf("%d",&n);
        pre();
        for (int i=1;i<=n;i++) 
        {
            scanf("%d",&a[i]);t[i]=i;
        }
        sort(t+1,t+n+1,cmp);
        int js=0;
        a[0]=-1;
        for (int i=1;i<=n;i++) 
        {
            if (a[t[i]]!=a[t[i-1]]) js++;
            rk[t[i]]=js;
        }
        for (int i=1;i<=n;i++) dp[i][1]=1;
        for (int j=2;j<=n;j++) 
        {
            memset(tree,0,sizeof(tree));
            add(rk[j-1],dp[j-1][j-1]);
            for (int i=j;i<=n;i++)
            {
                dp[i][j]=query(rk[i]);
                add(rk[i],dp[i][j-1]);
            }        
        }
    
        g[n]=dp[n][n];
        for (int i=n-1;i;i--)
        {
            for (int j=1;j<=n;j++) g[i]+=dp[j][i]*fac[n-i]%mod,g[i]%=mod;
            for (int j=i+1;j<=n;j++) 
                g[i]-=C(i,j)*g[j]%mod*fac[j-i]%mod,g[i]%=mod;
        }
        ll ans=0;
        for (int i=1;i<=n;i++) ans=(ans+g[i]+mod)%mod;
        cout<<ans;
    }
  • 相关阅读:
    当前流行的智能硬件产品整理
    一个桌面视频录制利器推荐--Snagit
    微信支付---退款的坑
    微信支付退款证书服务器配置
    Git安装和TortoiseGit详细使用教程【基础篇】
    通俗易懂,什么是.NET Core以及.NET Core能做什么
    向ASP.NET Core迁移
    SQLServer 查看SQL语句的执行时间
    SqlServer 2014 Enterprise 企业版下载与安装教程(附图片)
    SQL Server表分区
  • 原文地址:https://www.cnblogs.com/coco-night/p/9622933.html
Copyright © 2011-2022 走看看