Description 题目描述
魔法世界的庆典就要到了,大法师交给Chavo好多好多魔法丝带,要求Chavo为它们涂上五彩斑斓的颜色。Chavo把一条丝带等分成m段,将连续的几段涂上一种颜色。她有
n 种不同颜色的颜料,而且她会使用每一种颜色一次且仅一次。某一次涂色可能会覆盖掉之前已经涂上的颜色,但是她不会让一种颜色完全覆盖掉另外一种颜色。现在Chavo想知道,她有多少种不同的方案为一条丝带涂色?结果要对1000000007取模后输出。
设颜色A的起点为L1 ,终点为R1,颜色B的起点为L2 ,终点为R2,当L1≤L2≤R2≤R1时,颜色A完全覆盖颜色B 。每一种方案包含n对Li和Ri ,每一对Li和Ri代表一次涂色的起点和终点(1≤Li≤Ri≤m)。
两种方案不一样当且仅当一种方案里的某一次涂色的起点和终点在另外一种方案里不存在。
Input 输入
只有一行输入整数n和
m
Output 输出
输出一行带有一个整数代表有多少种画法满足题意,结果要对1000000007取模后输出。
Sample Input 样例输入
2 3
Sample Output 样例输出
6
Limits 限制
对于30%的数据,1≤n,m≤10
对于60%的数据,1≤n,m≤100
对于100%的数据,1≤n∗m≤100000
Time Limit : 2s & Memory Limit : 128MB
Hints 提示
6种情况为
由题意可知,对于任意两段颜色来说,设起点分别为L1,L2,终点分别为R1,R2。
若L1=L2,则无论R1,R2大小关系如何,必定一段颜色覆盖另一段,不满足题意。同理R1≠R2。
于是可以知道每一个位置最多是一种颜色的起点,一种颜色的终点。
令L1<L2(反之也是一样),若R1>R2,则第一段颜色覆盖第二段颜色,所以必有R1<R2
对任意两段颜色都成立,则对所有颜色都成立。
所以有L1<L2<...<Ln,则必有R1<R2<...<Rn,且L1≤R1,L2≤R2,...,Ln≤Rn。
由此可知,某个起点Li所对应的Ri与其位置无关,仅与已经确定的Ri的个数有关。
故考虑以下动态规划状态
dp[k][i][j]代表在已经确定前k−1个格子中有i个起点和
时间复杂度为
对于n∗m≤100000,考虑到如果n>m,则无解,故n≤m,
由此推出n2≤n∗m≤105,则n<333,则n2m≤3.33∗107,可以在时限内运行完。因为一个格子的状态只与上一个格子的状态有关,可以用滚动数组优化内存空间。
dp是个好东西啊……
上代码
#include<cstdio>
#define MOD 1000000007
int dp[2][333][333];
int n,m;
int i,j,k;
int main()
{
scanf("%d %d",&n,&m);
if(n>m)//特判
{
printf("0");
return 0;
}
dp[0][0][0]=1;//初始
for(k=1;k<=m;k++)
{
for(i=0;i<=n;i++)
for(j=0;j<=i;j++) //终点数应小于等于起点数
{ //运用与运算压缩空间 k&1的结果为k%2
dp[k&1][i][j]=dp[k-1&1][i][j];
//这一格既不是起点也不是终点
if(i) dp[k&1][i][j]=(dp[k-1&1][i-1][j]+dp[k&1][i][j])%MOD;
//以这一格为起点
if(j) dp[k&1][i][j]=(dp[k-1&1][i][j-1]+dp[k&1][i][j])%MOD;
//以这一格为终点
if(i&&j) dp[k&1][i][j]=(dp[k-1&1][i-1][j-1]+dp[k&1][i][j])%MOD;
//既以这一格为起点,又以这一格为终点
}
}
printf("%d",dp[m&1][n][n]%MOD);
return 0;
}