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; }