很容易想出一个dp算法,用
dp[i][j]
表示前
i
个学校,最后一个选颜色
于是我们可以离散化,但是这样光记录最后一个放在哪个区间是不够的了。可以用
dp[i][j][k]
表示前
i
个学校,第
转移也不复杂,
注意当
k=1
时,
dp[i][j][1]=dp[i−1][j][1]+∑j−1x=0∑i−1y=0dp[i][x][y]
,其中后一项可以前缀和优化。
复杂度是
O(n3)
,
在uoj上可以通过此题。但是在bzoj上被卡常,优化方法是记录每个区间目前被多少个位置覆盖,从而减少对
k
<script type="math/tex" id="MathJax-Element-2164">k</script>的枚举。
#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
const int p=1000000007,maxn=510;
int dp[2*maxn][maxn],sum[2*maxn],lim[2*maxn],inv[maxn],ord[maxn*2],l[maxn],r[maxn],
n,m;
int rd()
{
int x=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9')
{
x=x*10+c-'0';
c=getchar();
}
return x;
}
int pow(int b,int k)
{
int ret=1;
for (;k;k>>=1,b=(LL)b*b%p)
if (k&1) ret=(LL)ret*b%p;
return ret;
}
int inc(int x,int y)
{
x+=y;return x>=p?x-p:x;
}
int dec(int x,int y)
{
x-=y;return x<0?x+p:x;
}
int main()
{
/*freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);*/
int ans=0;
n=rd();
for (int i=1;i<=n;i++)
{
l[i]=rd();
r[i]=rd()+1;
ord[++m]=l[i];
ord[++m]=r[i];
}
sort(ord+1,ord+m+1);
m=unique(ord+1,ord+m+1)-ord-1;
for (int i=1;i<=n;i++)
{
l[i]=lower_bound(ord+1,ord+m+1,l[i])-ord;
r[i]=lower_bound(ord+1,ord+m+1,r[i])-ord;
}
for (int i=1;i<=n;i++) inv[i]=pow(i,p-2);
dp[0][0]=1;
for (int j=0;j<m;j++) sum[j]=1;
for (int i=1;i<=n;i++)
{
for (int j=l[i];j<r[i];j++)
{
lim[j]++;
for (int k=lim[j];k>1;k--)
dp[j][k]=inc(dp[j][k],(LL)dp[j][k-1]*(ord[j+1]-ord[j]-k+1)%p*inv[k]%p);
dp[j][1]=inc(dp[j][1],(LL)sum[j-1]*(ord[j+1]-ord[j])%p);
}
for (int j=1;j<m;j++)
{
sum[j]=sum[j-1];
for (int k=1;k<=lim[j];k++)
sum[j]=inc(sum[j],dp[j][k]);
}
}
printf("%d\n",dec(sum[m-1],1));
}