首先离散化一下,然后令f[i][j][k]表示做到第i个学校,最后一个数落在j号区间,这个区间里有k个不同的数的方案数。(实际上如果两个学校的数量是一样的,那么对后面的方案是没有影响的,所以记录的是k个不一样的数)。
sum[t]=∑f[i-1][j][p] (1<=j<=t)
f[i][j][k]=f[i-1][j][k]+f[i-1][j][k-1]*(len[j]-k+1)/k
f[i][j][1]=f[i-1][j][1]+sum[j-1]*len[j]
sum数组可以提前累加预处理出,注意预处理一下逆元即可。
还有就是注意sum的初始化!
#include<cmath>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<iomanip>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1000000000
#define mo 1000000007
#define N 1010
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
struct section{int l,r;} q[N],seq[N];
int a[N],dp[N][N],f[N][N],sum[N],len[N],inv[N];
int n,i,j,k,num,tot,res;
int qry_l(int x)
{
int l = 1,r = num,res;
while (l <= r)
{
int mid = (l + r) >> 1;
if (x <= seq[mid].l) res = mid,r = mid - 1; else l = mid + 1;
}
return res;
}
int qry_r(int x)
{
int l = 1,r = num,res;
while (l <= r)
{
int mid = (l + r) >> 1;
if (seq[mid].r < x) res = mid,l = mid + 1; else r = mid - 1;
}
return res;
}
int q_p(int x,int a)
{int res=1;while(a){if(a&1)res=(1ll*res*x)%mo;x=(1ll*x*x)%mo;a>>=1;}return res;}
int main()
{
fo(i,1,1000) inv[i] = q_p(i,mo-2);
scanf("%d",&n);
fo(i,1,n) {scanf("%d%d",&q[i].l,&q[i].r); q[i].r++; a[++tot] = q[i].l; a[++tot] = q[i].r;}
sort(a+1,a+tot+1);
fo(i,1,tot-1)
if (a[i]!=a[i+1])
{
num++;
seq[num].l = a[i]; seq[num].r = a[i+1]-1;
len[num] = a[i+1]-a[i];
}
fo(i,1,n) q[i].l = qry_l(q[i].l) , q[i].r = qry_r(q[i].r);
fo(i,1,n)
{
fo(j,1,num) dp[i][j] = dp[i-1][j];
fo(j,q[i].l,q[i].r) dp[i][j]++;
}
fo(i,0,num) sum[i] = 1;
fo(i,1,n)
{
fo(j,q[i].l,q[i].r)
{
fd(k,dp[i][j],2)
f[j][k] = (f[j][k] + (1ll*f[j][k-1]*(len[j]-k+1)%mo)*inv[k]%mo)%mo;
f[j][1] = (f[j][1] + 1ll*sum[j-1]*len[j]%mo)%mo;
}
sum[0] = 1;
fo(j,1,num)
{
sum[j] = sum[j-1];
fo(k,1,dp[i][j]) sum[j] = (sum[j] + f[j][k]) % mo;
}
}
printf("%d\n",sum[num]-1);
return 0;
}