zoukankan      html  css  js  c++  java
  • 题解 P3643 [APIO2016]划艇

    题解

    一种思路很好想:(f_{i,j}) 表示前 (i) 所学校中,第 (i) 所学校参赛且派出 (j) 艘划艇的方案数。(转移就不列了。)

    这种方式有一个致命点,就是 (j) 的范围是 (10^9),这样连 (9) 分都过不去。当我们看到这么大数据范围时,一般想的都是离散化。

    此时我们就可以设状态为:(f_{i,j}) 表示前 (i) 所学校中第 (i) 所学校参赛,且派出的划艇数落到第 (j) 个区间的方案数。因为一共有 (n) 个区间,所以 (j) 复杂度最多为 (mathcal O(n))

    所以在第 (i) 所学校之前的学校可以分为两种,在区间 (j) 的和不在的。

    引理 :

    若要从 ([0,L]) 中选出 (n) 个数,其中非零数严格递增,则有 ((^{L+n}_{kern 0.6em n})) 种可能

    (证明请看别的大佬的题解)

    那么对于本题来说,因为我们设的第 (i) 所学校必须参赛,所以计算 (0) 时答案需要减 (-1) ,方案数即为 ((^{m-1+L}_{;;; m}))(m) 表示挑选划艇个数在第 (j) 个区间的学校的数量。

    那么转移方程容易得出:

    [f_{i,j}=left{ egin{array}{l} sum_{p=1}^{i-1}sum_{k=1}^{j-1}(^{m+L-1}_{;;; m})f_{p,k} kern 1.5emjin [a_i,b_i] \ 0 kern 10.8emj otin [a_i,b_i]\ end{array} ight. ]

    对于 (sum_{p=1}^{i-1}sum_{k=1}^{j-1}(^{m+L-1}_{;;; m})f_{p,k}) 我们可以用一个前缀和处理一下

    则设 (g_{i,j}=sum_{k=1}^{j}f_{i,k})

    那么最后的转移为

    [f_{i,j}=sum_{p=1}^{i-1}(^{m+L-1}_{;;; m})g_{p,j-1} ;;; jin[a_i,b_i] ]

    Code
    #include<bits/stdc++.h>
    #define ri register int
    #define p(i) ++i
    using namespace std;
    namespace IO{
        char buf[1<<21],*p1=buf,*p2=buf;
        inline char gc() {return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
        inline int read() {
            ri x=0,f=1;char ch=gc();
            while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
            while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
            return x*f;
        }
    }
    using IO::read;
    namespace nanfeng{
        #define ll long long
        static const int N=550;
        static const int MOD=1e9+7;
        int inv[N],a[N],b[N],num[N<<1],C[N],g[N],tot,n;
        inline int main() {
            n=read();
            inv[1]=1;
            for (ri i(2);i<=n;p(i)) inv[i]=1ll*(MOD-MOD/i)*inv[MOD%i]%MOD;
            for (ri i(1);i<=n;p(i)) {
                a[i]=read(),b[i]=read();
                num[p(tot)]=a[i];num[p(tot)]=b[i]+1;
            }
            sort(num+1,num+tot+1);
            tot=unique(num+1,num+tot+1)-num-1;
            for (ri i(1);i<=n;p(i)) {
                a[i]=lower_bound(num+1,num+tot+1,a[i])-num;
                b[i]=lower_bound(num+1,num+tot+1,b[i]+1)-num;
            }
            C[0]=g[0]=1;
            for (ri j(1);j<tot;p(j)) {
                int len=num[j+1]-num[j];
                for (ri i(1);i<=n;p(i)) C[i]=(ll)C[i-1]*(ll)(len+i-1)%MOD*inv[i]%MOD;
                for (ri i(n);i;--i) {
                    if (a[i]<=j&&j+1<=b[i]) {
                        int f=0,cnt=1,l=C[1];
                        for (ri k(i-1);k>=0;--k) {
                            f=(f+(ll)l*g[k]%MOD)%MOD;
                            if (a[k]<=j&&j+1<=b[k]) l=C[p(cnt)];
                        }
                        g[i]=(g[i]+f)%MOD;
                    }
                } 
            }
            int ans=0;
            for (ri i(1);i<=n;p(i)) ans=(ans+g[i])%MOD;
            printf("%lld
    ",ans);
            return 0;
        }
        // #undef int
    }
    int main() {return nanfeng::main();}
    

    复杂度为 (mathcal O(n^3))

  • 相关阅读:
    个人网址收集
    使用 TListView 控件(2)
    C# 语法练习(14): 类[六] 事件
    如何在 "万一的 Delphi 博客" 回复自动格式化的着色代码?
    使用 TListView 控件(1)
    C# 语法练习(13): 类[五] 索引器
    使用 TListView 控件(4)
    C# 语法练习(11): 类[三] 构造函数、析构函数、base、this
    C# 语法练习(12): 类[四] 抽象类与抽象成员、密封类与密封成员
    使用 TListView 控件(3)
  • 原文地址:https://www.cnblogs.com/nanfeng-blog/p/14801998.html
Copyright © 2011-2022 走看看