2020百度之星初赛三.Chess(滚动dp)

这题其实也不难,但是坑点蛮多的

由 于 题 目 说 有 可 能 获 胜 就 行 , 所 以 只 要 连 续 传 送 带 不 多 于 10 个 就 合 法 由于题目说有可能获胜就行,所以只要连续传送带不多于10个就合法 ,10

Ⅰ . 当 多 于 10 个 , 无 论 如 何 无 法 通 过 这 片 区 域 就 会 回 退 \color{Red}Ⅰ.当多于10个,无论如何无法通过这片区域就会回退 .10,退

Ⅱ . 不 多 于 10 个 , 由 于 每 次 扔 筛 子 , 总 有 办 法 不 经 过 一 次 传 送 带 到 达 终 点 \color{Red}Ⅱ.不多于10个,由于每次扔筛子,总有办法不经过一次传送带到达终点 .10,,

那 么 定 义 d p [ i ] [ j ] [ q ] 为 截 至 到 i 个 格 子 放 了 j 个 传 送 带 , 且 目 前 连 续 放 了 q 个 传 送 带 那么定义dp[i][j][q]为截至到i个格子放了j个传送带,且目前连续放了q个传送带 dp[i][j][q]ij,q

如果决策在 i i i这个位置放传送,可以传送到的位置有 ∈ [ 1 , i − 1 ] \in[1,i-1] [1,i1],方案乘上(i-1)

Ⅰ . 那 么 当 q = 0 时 , d p [ i ] [ j ] [ q ] = ∑ s = 0 s = 10 d p [ i − 1 ] [ j ] [ s ] Ⅰ.那么当q=0时,dp[i][j][q]=\sum_{s=0}^{s=10}dp[i-1][j][s] .q=0,dp[i][j][q]=s=0s=10dp[i1][j][s]

解 释 : 当 前 位 置 不 放 传 送 , 可 以 从 任 意 一 个 位 置 转 移 来 \color{Red}解释:当前位置不放传送,可以从任意一个位置转移来 :,


Ⅱ . 当 q = 1 时 , d p [ i ] [ j ] [ q ] = d p [ i − 1 ] [ j − 1 ] [ 0 ] ∗ ( i − 1 ) Ⅱ.当q=1时,dp[i][j][q]=dp[i-1][j-1][0]*(i-1) .q=1,dp[i][j][q]=dp[i1][j1][0](i1)

解 释 : 当 前 位 置 放 了 连 续 1 个 传 送 , 那 么 前 一 个 位 置 不 应 该 有 传 送 \color{Red}解释:当前位置放了连续1个传送,那么前一个位置不应该有传送 :1,


Ⅲ . 当 q ∈ [ 2 , 10 ] , d p [ i ] [ j ] [ q ] = d p [ i − 1 ] [ j ] [ q − 1 ] ∗ ( i − 1 ) Ⅲ.当q\in[2,10],dp[i][j][q]=dp[i-1][j][q-1]*(i-1) .q[2,10],dp[i][j][q]=dp[i1][j][q1](i1)

解 释 : 放 传 送 且 接 着 上 次 的 连 续 传 送 \color{Red}解释:放传送且接着上次的连续传送 :

但是这么开数组会炸,所以用滚动数组

#include 
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll n,t,m,dp[2][1009][12],ans,cha[1009][1009];
void DP()
{
	//定义dp[i][j][q]为前i个格子放j个传送带,且当前连续放了q个传送带 
	dp[0][1][1]=1;
	dp[0][0][0]=1;//初始状态其实是n=3的情况,此时只能在n=2的格子放或者不放 
	cha[2][1]=cha[2][0]=1;
	for(int i=3;i<=1000;i++)//计算从在[2,n-1]区间内放j个传送带的情况 
	{
		int t=i&1;//滚动数组 
		memset(dp[t],0,sizeof(dp[t]));
		for(int j=0;j<=1000;j++)//到i格子放了j个传送带
		{	
			if( j>0 )
				dp[t][j][1]=dp[t^1][j-1][0]*(i-1)%mod;//新开一片区域放传送带,此时可以传送到前面的i-1个位置 
			for(int q=0;q<=10;q++)
			{
				dp[t][j][0]+=dp[t^1][j][q];//啥都不放,从所有状态转移而来 
				dp[t][j][0]%=mod;
			}
			for(int q=2;q<=10;q++)
			{
				if( j>0 )
					dp[t][j][q]+=dp[t^1][j-1][q-1]*(i-1);
				dp[t][j][q]%=mod;
			}
		}
		for(int j=0;j<=1000;j++)//空间不够,开数组 
		for(int q=0;q<=10;q++)
		{
			cha[i][j]+=dp[t][j][q];
			cha[i][j]%=mod;
		}
	}
}
int main()
{
	scanf("%lld",&t);
	DP();
	while( t-- )
	{
		scanf("%lld%lld",&n,&m);
		if( m==0 )
		{
			printf("1\n");
			continue;
		}
		int s=(n-2)/(11);
		int temp=s*10+(n-2)%11; 
		if( m>temp )
		{
			printf("-1\n");
			continue;
		}
		//前面全都是特判 
		printf("%lld\n",cha[n-1][m]);
	}
}

你可能感兴趣的:(Dp似神仙)