UOJ#204 【APIO2016】Boat

Time Limit: 70 Sec  Memory Limit: 256 MB
Submit: 559  Solved: 248

Description

在首尔城中,汉江横贯东西。在汉江的北岸,从西向东星星点点地分布着个划艇学校,编号依次为到。每个学校都
拥有若干艘划艇。同一所学校的所有划艇颜色相同,不同的学校的划艇颜色互不相同。颜色相同的划艇被认为是一
样的。每个学校可以选择派出一些划艇参加节日的庆典,也可以选择不派出任何划艇参加。如果编号为的学校选择
派出划艇参加庆典,那么,派出的划艇数量可以在Ai至Bi之间任意选择(Ai<=Bi)。值得注意的是,编号为i的学
校如果选择派出划艇参加庆典,那么它派出的划艇数量必须大于任意一所编号小于它的学校派出的划艇数量。输入
所有学校的Ai、Bi的值,求出参加庆典的划艇有多少种可能的情况,必须有至少一艘划艇参加庆典。两种情况不同
当且仅当有参加庆典的某种颜色的划艇数量不同

Input

 第一行包括一个整数N,表示学校的数量。接下来N行,每行包括两个正整数,用来描述一所学校。其中第行包括的

两个正整数分别表示Ai,Bi(1<=Ai<=Bi<=10^9),N<=500

Output

 输出一行,一个整数,表示所有可能的派出划艇的方案数除以1,000,000,007得到的余数

Sample Input

2
1 2
2 3

Sample Output

7

HINT

Source

 

动态规划

看着题解懵X一个多小时,我这么弱已经没救了吧

枚举数量显然无力,我们得考虑将整段区间一起处理,于是先将区间离散化

将派船看作在限定区间里选一个数,设f[i][j][k]表示当前枚举到第i个学校,最大船数在第j段,这段里选了k个数的方案数。

$ f[i][j][k]=f[i-1][j][k]+f[i-1][j][k-1]* \frac {C(len[j],k)}{C(len[j],k-1)} $

特殊处理 $ f[i][j][1]=f[i-1][j][1] + (\sum_{a=1}^{j-1}  \sum_{k=0}^{i-1} f[i-1][a][k] )*len[j] $

第一维可以滚动优化掉

第一个式子的组合数,约分一下变成了(len-k+1)/k ,预处理500以内的逆元即可。

第二个式子用前缀和优化。

然后大概就能过了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define LL long long
 6 using namespace std;
 7 const int mod=1e9+7;
 8 const int mxn=1105;
 9 int read(){
10     int x=0,f=1;char ch=getchar();
11     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
12     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
13     return x*f;
14 }
15 int inv[mxn];
16 void init(){
17     inv[0]=inv[1]=1;
18     for(int i=2;i<mxn;i++){
19         inv[i]= ((-mod/i)*(LL)inv[mod%i]%mod+mod)%mod;
20     }
21     return;
22 }
23 int n;
24 int c[mxn][mxn];
25 struct seg{
26     int L,R;
27 }a[mxn];
28 int pos[mxn],sz=0,len[mxn];
29 int f[mxn][mxn],g[mxn];
30 int num[mxn];
31 int main(){
32 //    freopen("boat.in","r",stdin);
33 //    freopen("boat.out","w",stdout);
34     int i,j;
35     n=read();
36     init();
37     for(i=1;i<=n;i++){
38         a[i].L=read()-1;a[i].R=read();
39         pos[++sz]=a[i].L;pos[++sz]=a[i].R;
40     }
41     sort(pos+1,pos+sz+1);
42     sz=unique(pos+1,pos+sz+1)-pos-1;
43 //    for(i=1;i<=sz;i++)printf("%d",pos[i]);
44     for(i=1;i<=n;i++){
45         a[i].L=lower_bound(pos+1,pos+sz+1,a[i].L)-pos;
46         a[i].R=lower_bound(pos+1,pos+sz+1,a[i].R)-pos;
47     }
48     for(i=1;i<=sz;i++)len[i]=pos[i]-pos[i-1];
49     f[0][1]=1;
50     for(i=1;i<=sz;i++)g[i]=1;
51     for(i=1;i<=n;i++){
52         for(j=a[i].L+1;j<=a[i].R;j++){
53             num[j]++;
54             for(int k=num[j];k>1;k--)
55                 f[j][k]=((LL)f[j][k]+(LL)f[j][k-1]*(len[j]-k+1)%mod*(LL)inv[k])%mod;
56             f[j][1]=((LL)f[j][1]+(LL)g[j-1]*len[j]%mod)%mod;
57         }
58         for(j=a[i].L+1;j<=sz;j++){
59             g[j]=g[j-1];
60             for(int k=num[j];k;k--){
61                 g[j]=((LL)g[j]+f[j][k])%mod;
62             }
63         }
64     }
65     g[sz]--;if(g[sz]<=0)g[sz]+=mod;
66     printf("%d\n",g[sz]);
67     return 0;
68 }

 

posted @ 2017-05-09 12:19  SilverNebula  阅读(374)  评论(0编辑  收藏  举报
AmazingCounters.com