题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=4584

题解

首先将BiB_i11,把派出的数量变成左闭右开的区间,将AiA_iBiB_i离散化,把题目涉及的区间变成一段段左闭右开的区间。例如,假设给出了[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)
可以证明,离散化之后的区间个数不超过2n12n-1

f[i][j][k]f[i][j][k]表示前ii个位置,第ii个位置必须派出,派出的数量在离散化后的第jj个区间内,派出数量在这个区间内的一共有kk个位置的方案数。
f[i][j][1]=i=0i1j=0j1k=1nf[i][j][k]f[i][j][k]=i=0i1f[i][j][k1](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)
这个还算比较好理解的,后面两个东西用前缀和转移即可,然后你就会发现ff数组没有存在的必要了,可以去掉(卡常,不加这个过不了),最后ff数组的前缀和-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;
}