纪中暑假集训 2020.08.05【NOIP提高组】模拟 T1:【NOIP2015模拟11.5】俄罗斯套娃

俄罗斯套娃

Description

在这里插入图片描述

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

10 1000

Sample Output

3628800

Data Constraint

在这里插入图片描述

反思&题解

比赛思路: 暴力枚举全排列判断
正解思路: f [ i ] [ j ] f[i][j] 表示考虑了前i个数,逆序对为j的排列数,易得方程为: f [ i ] [ j ] = f [ i 1 ] [ k ] ( j i k j ) f[i][j]=\sum^f[i-1][k](j-i≤k≤j) ,又因为求的是连续一段的和,所以我们预处理一下前缀和就可以将复杂度优化到 O ( n 2 ) O(n^2) (还有这题空间极其恶心,要开滚动数组)
反思: 比赛的时候状态设得有问题,所以一直推不出来,对于DP的感觉还是要多练

CODE

#include<bits/stdc++.h>
using namespace std;
const long long mo=10000000007;
long long f[2][3005],n,k,sum[3005];
int main()
{
	freopen("matryoshka.in","r",stdin);
	freopen("matryoshka.out","w",stdout);
	scanf("%lld%lld",&n,&k);
	long long i,j,x=1;
	for (i=0;i<=k;i++)
		sum[i]=1;
	f[0][0]=1;
	for (i=1;i<=n;i++)
	{
		for (j=0;j<=min(k,i*(i-1)/2);j++)
		{
			if (j-i+1>0) f[x][j]=(sum[min(j,(i-1)*(i-2)/2)]-(sum[j-i])+mo)%mo;
			else f[x][j]=sum[min(j,(i-1)*(i-2)/2)];
 		}
		for (j=0;j<=k;j++)
		{
			sum[j]=0;
			f[x^1][j]=0;
		}
		sum[0]=f[x][0];
		for (j=1;j<=k;j++)
			sum[j]=(sum[j-1]+f[x][j])%mo;
		x^=1;	
	}
	printf("%lld\n",sum[k]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/CMC_YXY/article/details/107826217
今日推荐