BZOJ4584 APIO2016赛艇(动态规划+组合数学)

  如果值域不大,容易想到设f[i][j]为第i个学校选了j的方案数,枚举上一个学校是哪个选了啥即可,可以前缀和优化。于是考虑离散化,由于离散化后相同的数可能可以取不同的值,所以枚举第一个和其所选数(离散化后)相同的学校是哪个,考虑这一段里选几个学校怎么选数,组合数即可。各种显然的优化后即可做到O(n3),瞎卡卡常就……根本过不了。被卡常已经习惯了。不要把有限的生命投入无限的卡常之中。越菜的人越容易被卡常。——沃兹基硕德。luogu8s,darkbzoj40s,bzoj?s。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 510
#define P 1000000007
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int n,a[N],b[N],f[N][N<<2],g[N][N<<2],C[N][N],c[N],h[N<<2][N],u[N<<2],v[N<<2],l[N<<2],r[N<<2],last[N][N<<2],tot[N<<2],t;
void inc(int &x,int y){x+=y;if (x>=P) x-=P;}
int inv(int a)
{
    int s=1,k=P-2;
    for (;k;k>>=1,a=1ll*a*a%P) if (k&1) s=1ll*s*a%P;
    return s;
}
void pre()
{
    sort(v+1,v+t+1);
    t=unique(v+1,v+t+1)-v-1;int t2=0;
    u[++t2]=v[1];l[t2]=r[t2]=v[1];
    for (int i=2;i<=t;i++)
    {
        if (v[i]-1!=v[i-1]) u[++t2]=v[i]-1,l[t2]=v[i-1]+1,r[t2]=v[i]-1;
        u[++t2]=v[i],l[t2]=v[i],r[t2]=v[i];
    }
    t=t2;memcpy(v,u,sizeof(v));
    for (int i=1;i<=n;i++) a[i]=lower_bound(v+1,v+t+1,a[i])-v,b[i]=lower_bound(v+1,v+t+1,b[i])-v;
    for (int i=1;i<=t;i++)
    {
        int l=0;
        for (int j=1;j<=n;j++)
        if (a[j]<=i&&i<=b[j]) last[j][i]=l,tot[i]++,l=j;
        else last[j][i]=0;
    }
}
void calc()
{
    C[0][0]=1;
    for (int i=1;i<=n;i++)
    {
        C[i][0]=C[i][i]=1;
        for (int j=1;j<i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
    }
    for (int i=1;i<=t;i++)
    {
        memset(c,0,sizeof(c));
        c[0]=1;
        for (int j=1;j<=n&&j<=r[i]-l[i]+2;j++)
        c[j]=1ll*c[j-1]*(r[i]-l[i]+1-j+1)%P*inv(j)%P;
        for (int j=2;j<=tot[i];j++)
            for (int p=2;p<=j;p++)
            inc(h[i][j],1ll*C[j-2][p-2]*c[p]%P);
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4584.in","r",stdin);
    freopen("bzoj4584.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read();
    for (int i=1;i<=n;i++) v[++t]=a[i]=read(),v[++t]=b[i]=read();
    pre();calc();
    f[0][0]=1;for (int i=0;i<=t;i++) g[0][i]=1;
    for (int i=1;i<=n;i++)
    {
        for (int j=a[i];j<=b[i];j++)
        {
            f[i][j]=1ll*g[i-1][j-1]*(r[j]-l[j]+1)%P;
            int cnt=1;
            for (int k=last[i][j];k;k=last[k][j])
            inc(f[i][j],1ll*g[k-1][j-1]*h[j][++cnt]%P);
        }
        for (int j=1;j<=t;j++) g[i][j]=(g[i][j-1]+f[i][j])%P;
        for (int j=0;j<=t;j++) inc(g[i][j],g[i-1][j]);
    }
    cout<<(g[n][t]+P-1)%P;
    return 0;
}

 

posted @ 2018-11-03 02:00  Gloid  阅读(226)  评论(0编辑  收藏  举报