题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=4584
题解
首先将BiB_iBi加111,把派出的数量变成左闭右开的区间,将AiA_iAi和BiB_iBi离散化,把题目涉及的区间变成一段段左闭右开的区间。例如,假设给出了[1,4],[2,5],[3,6][1,4],[2,5],[3,6][1,4],[2,5],[3,6]这三个数量的区间,那么离散化之后就变成了
[1,4]→[1,2),[2,3),[3,5)[2,5]→[2,3),[3,5),[5,6)[3,6]→[3,5),[5,6),[6,7) [1,4] \rightarrow [1,2),[2,3),[3,5)\\ [2,5] \rightarrow [2,3),[3,5),[5,6)\\ [3,6] \rightarrow [3,5),[5,6),[6,7) [1,4]→[1,2),[2,3),[3,5)[2,5]→[2,3),[3,5),[5,6)[3,6]→[3,5),[5,6),[6,7)
可以证明,离散化之后的区间个数不超过2n−12n-12n−1。
设f[i][j][k]f[i][j][k]f[i][j][k]表示前iii个位置,第iii个位置必须派出,派出的数量在离散化后的第jjj个区间内,派出数量在这个区间内的一共有kkk个位置的方案数。
f[i][j][1]=∑i′=0i−1∑j′=0j−1∑k=1nf[i′][j′][k]f[i][j][k]=∑i′=0i−1f[i′][j][k−1](k>1) f[i][j][1]=\sum_{i'=0}^{i-1} \sum_{j'=0}^{j-1} \sum_{k=1}^n f[i'][j'][k]\\ f[i][j][k]=\sum_{i'=0}^{i-1} f[i'][j][k-1](k>1) f[i][j][1]=i′=0∑i−1j′=0∑j−1k=1∑nf[i′][j′][k]f[i][j][k]=i′=0∑i−1f[i′][j][k−1](k>1)
这个还算比较好理解的,后面两个东西用前缀和转移即可,然后你就会发现fff数组没有存在的必要了,可以去掉(卡常,不加这个过不了),最后fff数组的前缀和-1就是答案。
代码
#include
#include
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;
}