题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=4584
题解
首先将加,把派出的数量变成左闭右开的区间,将和离散化,把题目涉及的区间变成一段段左闭右开的区间。例如,假设给出了这三个数量的区间,那么离散化之后就变成了
可以证明,离散化之后的区间个数不超过。
设表示前个位置,第个位置必须派出,派出的数量在离散化后的第个区间内,派出数量在这个区间内的一共有个位置的方案数。
这个还算比较好理解的,后面两个东西用前缀和转移即可,然后你就会发现数组没有存在的必要了,可以去掉(卡常,不加这个过不了),最后数组的前缀和-1就是答案。
代码
#include <cstdio>
#include <algorithm>
int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int maxn=500;
const int mod=1000000007;
int n,l[maxn+10],r[maxn+10],d[maxn*2+10],tot,len[maxn*2+10],sum[maxn+10][maxn*2+10],inv[maxn+10],sf[maxn*2+10][maxn+10];
int main()
{
n=read();
for(int i=1; i<=n; ++i)
{
l[i]=read();
r[i]=read();
d[++tot]=l[i];
d[++tot]=r[i]+1;
}
std::sort(d+1,d+tot+1);
tot=std::unique(d+1,d+tot+1)-d-1;
for(int i=1; i<=n; ++i)
{
l[i]=std::lower_bound(d+1,d+tot+1,l[i])-d;
r[i]=std::lower_bound(d+1,d+tot+1,r[i]+1)-d;
}
for(int i=1; i<tot; ++i)
{
len[i]=d[i+1]-d[i];
}
inv[1]=1;
for(int i=2; i<=n; ++i)
{
inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
}
for(int i=0; i<=tot; ++i)
{
sum[0][i]=1;
}
for(int i=1; i<=n; ++i)
{
for(int j=0; j<l[i]; ++j)
{
sum[i][j]=sum[i-1][j];
}
for(int j=l[i]; j<r[i]; ++j)
{
int fuck=1ll*len[j]*sum[i-1][j-1]%mod,pps=fuck;
for(int k=i; k>1; --k)
{
int h=1ll*sf[j][k-1]*(len[j]-k+1)%mod*inv[k]%mod;
pps+=h;
if(pps>=mod)
{
pps-=mod;
}
sf[j][k]+=h;
if(sf[j][k]>=mod)
{
sf[j][k]-=mod;
}
}
sf[j][1]+=fuck;
if(sf[j][1]>=mod)
{
sf[j][1]-=mod;
}
sum[i][j]=(1ll*sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+pps)%mod;
if(sum[i][j]<0)
{
sum[i][j]+=mod;
}
}
for(int j=r[i]; j<=tot; ++j)
{
sum[i][j]=(1ll*sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1])%mod;
if(sum[i][j]<0)
{
sum[i][j]+=mod;
}
}
}
printf("%d\n",(sum[n][tot]+mod-1)%mod);
return 0;
}