记录编号 359806 评测结果 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
题目名称 [APIO2016]划艇 最终得分 100
用户昵称 GravatarFoolMike 是否通过 通过
代码语言 C++ 运行时间 28.267 s
提交时间 2016-12-25 00:24:52 内存使用 8.11 MiB
显示代码纯文本
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
const int N=1010,p=1e9+7;
typedef long long ll;
set<int> S;
int n,cnt,a[N],b[N],A[N],l[N];
int find(int x,int l,int r){
	if (l==r) return l;
	int mid=(l+r)>>1;
	return A[mid]>=x?find(x,l,mid):find(x,mid+1,r);
}
ll dp[N][N],inv[N];
//dp[i][j]表示最后一个取到第i个学校,该校派出[A[i],A[i+1])只代表队的方案数。
//最后用前缀和算。 
int main()
{
	freopen("boat.in","r",stdin);
	freopen("boat.out","w",stdout);
	scanf("%d",&n);
	inv[1]=1;
	for (int i=2;i<=n;i++)
		inv[i]=(p-p/i)*inv[p%i]%p;
	for (int i=1;i<=n;i++){
		scanf("%d%d",&a[i],&b[i]);
		if (!S.count(a[i])) S.insert(a[i]);
		if (!S.count(b[i]+1)) S.insert(b[i]+1);
	}
	for (set<int>::iterator i=S.begin();i!=S.end();++i) A[cnt++]=*i;
	for (int i=1;i<cnt;i++) l[i]=A[i]-A[i-1];
	for (int i=1;i<=n;i++){
        a[i]=upper_bound(A,A+cnt,a[i])-A;
        b[i]=upper_bound(A,A+cnt,b[i])-A;
    }
	for (int i=0;i<cnt;i++) dp[0][i]=1;
	for (int i=1;i<=n;i++){
		dp[i][0]=1;
		for (int j=a[i];j<=b[i];j++){
			dp[i][j]=dp[i-1][j-1]*l[j]%p;
			int c=l[j]-1,now=1;//c恒为C[now][l+now-2] 
			for (int k=i-1;k;k--)
			if (a[k]<=j&&j<=b[k]){
				now++;
				c=(ll)c*(l[j]+now-2)%p*inv[now]%p;
				if (!c) break;
				dp[i][j]=(dp[i][j]+dp[k-1][j-1]*c)%p;
			}
		}
		for (int j=1;j<cnt;j++)
			dp[i][j]=(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+dp[i][j])%p;
	}
	printf("%lld\n",(dp[n][cnt-1]-1+p)%p);
	return 0;
}