卧薪尝胆,厚积薄发。
Beautiful Pairs of Numbers
Date: Fri Nov 02 13:18:12 CST 2018 In Category: NoCategory

Description:

一个正整数对序列 $(a_1, b_1),(a_2, b_2),\dots,(a_k,b_k)$ 是美观的当且仅当满足:
  • $1\leqslant a_1\leqslant b_1<a_2\leqslant b_2<\dots <a_k\leqslant b_k\leqslant n$ 。
  • $b_1-a_1,b_2-a_2,\dots,b_k-a_k$ 两两不同。
给出 $n$ 和 $k$ ,求出美观序列的个数。
$1\leqslant testcases\leqslant2\times 10^5,1\leqslant n,k\leqslant 10^3$

Solution:

首先抽象一下问题,就是在数轴上 $[1,n]$ 放很多不相交的线段,所有线段长度不同,问有多少种方法,首先可以注意到线段的总个数不会超过 $50$ ,因为 $1+2+4+\cdots+50>1000$ ,那也就是说可以承受比 $O(nk)$ 复杂度更高的做法,不妨假设线段长度是递增的,那么我们设 $DP$ 状态为 $f[i][j][k]$ 表示已经放了 $i$ 个线段,总长度为 $j$ ,最长的线段长度小于 $k$ 的方案数,初值为 $f[0][0][1]=1$ ,转移为 $f[i+1][j+k][k+1]+=f[i][j][k]$ ,注意每次要把 $f[i][j][]$ 做个前缀和,复杂度为 $O(\sqrt N\times N\times N)$ ,然后求答案的时候先把 $f[i][j][k]$ 乘上 $i!$ ,然后要把一些空位插到线段之间,我们现在有 $i+1$ 个间隔和 $n-j$ 个空位,按照组合数学中的做法可以得到答案为 $i+n-j\choose n-j$ ,乘起来求和就是答案。
发现有一个更好理解的做法, $f[i][j][k]$ 本质是一个两两不同的整数划分数,直接用 $g[i][j]=g[i][j-i]+g[i-1][j-i]$ 求解即可。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
#define MAXN 1001
#define MOD 1000000007
void updata(int &x,int y){x = (x + y) % MOD;return;}
int g[51][MAXN];
int fac[MAXN];
#define MAX 2001
int C[MAX][MAX];
int ans[MAXN][MAXN];
int main()
{
g[0][0] = 1;
for(int i = 1;i <= 50;++i)
for(int j = i;j < MAXN;++j)
updata(g[i][j],g[i][j - i] + g[i - 1][j - i]);
fac[0] = 1;
for(int i = 1;i < MAXN;++i)fac[i] = 1ll * fac[i - 1] * i % MOD;
for(int i = 1;i <= 50;++i)
for(int j = 0;j < MAXN;++j)
g[i][j] = 1ll * g[i][j] * fac[i] % MOD;
C[0][0] = 1;
for(int i = 1;i < MAX;++i)
{
C[i][0] = C[i][i] = 1;
for(int j = 1;j < i;++j)
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
}
memset(ans,0,sizeof(ans));
for(int n_ = 1;n_ < MAXN;++n_)
for(int i = 1;i * (i + 1) / 2 <= n_;++i)
for(int j = 1;j <= n_;++j)
updata(ans[n_][i],1ll * g[i][j] * C[i + n_ - j][n_ - j] % MOD);
int testcases;
scanf("%d",&testcases);
int n,k;
while(testcases--)
{
scanf("%d%d",&n,&k);
if(n == 1 && k == 1)puts("1");
else printf("%d\n",ans[n][k]);
}
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡