题解 第四题

传送门

首先有个审题问题:那个 \(p\) 是最大值,所以 \(p_i \leqslant p_{i-1}+1\) 指的实际上是位置 \(i\) 的数最多比前面的数的最大值大1
我因为看成最多比 \(i-1\) 位置上的数大1浪费了不少时间

  • 对计数题求 \(\sum k^2\),其中 \(k\) 为所有组合/方案中某种元素出现次数的处理方法:

    \[k^2 = 2*\binom{k}{2}+k \]

    可以先把 \(k^2\) 化为从所有出现位置中选两个的选法数
    貌似仍然不好统计,先考虑如何对一种固定的方案求这个选法数
    可以脑残 \(n^2\) 枚举元素
    推广到对于一个位置 \(i\),从 \(i\) 之后的部分不固定
    \(i\) 的贡献就是 \(2 \times\)\(i\)之后的位置选出一个这种元素的方案数\(+2\)
    同理推广,每种方案的贡献是 1+在后面再选一个的方案数×2
    这部分证明及分析是水过去的,需要问明白

具体到这题……
image

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 3010
#define ll long long
#define reg register int
//#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
ll mod, f[N][N], g[N][N], ans[N];

signed main()
{
	n=read(); mod=read();
	f[0][0]=1;
	for (int i=1; i<=n; ++i) g[0][i]=1;
	for (int i=1; i<=n; ++i)
		for (int j=1; j<=n; ++j) {
			f[i][j]=(f[i-1][j]*j%mod+f[i-1][j-1])%mod;
			g[i][j]=(g[i-1][j]*j%mod+g[i-1][j+1])%mod;
		}
	for (int i=1; i<=n; ++i) {
		ll sum=0;
		for (int x=n; x; --x) {
			sum=(sum+f[i-1][x]*(g[n-i][x]+2ll*(n-i)%mod*g[n-i-1][x]%mod)%mod)%mod;
			ans[x]=(ans[x]+sum+f[i-1][x-1]*(g[n-i][x]+2ll*(n-i)%mod*g[n-i-1][x]%mod)%mod)%mod;
		}
	}
	for (int i=1; i<=n; ++i) printf("%lld ", ans[i]);
	printf("\n");
	
	return 0;
}
posted @ 2021-09-12 06:57  Administrator-09  阅读(7)  评论(0编辑  收藏  举报