首页 > 其他 > 详细

Solution -「ARC 104D」Multiset Mean

时间:2020-10-14 22:43:30      阅读:58      评论:0      收藏:0      [点我收藏+]

\(\mathcal{Description}\)

??Link.

??读题时间≈想题时间,草。(

??给定 \(N,K,M\),对于每个 \(x\in[1,N]\) 的整数 \(x\),统计多重集 \(\{s\}\) 的个数,使得集合元素的平均数为 \(x\),且满足对于任意 \(i\)\(s_i\in[1,N]\)\(\sum_j[s_i=s_j]\le K\),即相同元素至多出现 \(K\) 次。答案对 \(M\) 取模。

??\(N,K\le100\)

\(\mathcal{Solution}\)

??首先,看到“平均数”“中位数”之类的 AtCoder 比较喜欢的东西,肯定要进行转化。这里可以转化为“偏移量”:假设已钦定平均数 \(x\),那么一个元素 \(v\) 的贡献就是 \(v-x\),最终满足贡献和为 \(0\) 即可。对于任意多重集 \(\{s\}\),记 \(i\) 在其中出现的次数为 \(k_i~(i\in[1,N])\),那么:

\[\begin{aligned} &\sum_{i=1}^nik_i=x|\{s\}|\\Leftrightarrow &\sum_{i=1}^n(i-x)k_i=0\\Leftrightarrow &\sum_{i=1}^{x-1}(x-i)k_i=\sum_{i=x+1}^n(i-x)k_i \end{aligned} \]

??写着形象点就是满足:

\[k_{x-1}+2k_{x-2}+\cdots+(x-1)k_1=k_{x+1}+2k_{x+2}+\cdots+(n-x)k_n \]

??然后非常 amazing 地发现等号左右描述的是同一形式的问题:求 \(\{k_n\}\) 的个数,使得 \(\sum_{i=1}^nik_i=s\),且满足 \(k_i\in[0,K]\),其中 \(n,s\) 是形式参数。这个问题显然可以 DP:令 \(f(i,j)\) 表示 \(\sum_{t=1}^itk_t=j\) 的方案数,枚举新加入的 \(k_{i+1}\) 的值即可转移。

??第一维大小显然为 \(n\),考虑第二维的大小,我们只需要求出能使等式左右两边同时取到的 \(j\) 值。所以 \(j\le K(1+2+\cdots+\lfloor\frac{n}2\rfloor)\)

??最后,求答案时,枚举等式左右同时取到的值,乘法原理乘起来,别忘了乘上 \(k_x\)\(K+1\) 种取值,在减去空集的 \(1\)。(真啰嗦 owo。

??总复杂度 \(\mathcal O(N^3K^2)\) 带小于 \(\frac{1}8\) 的巨小常数(有问题欢迎指出 w),DP 建议刷表,考虑到无用状态数较多,跑得可快啦!

\(\mathcal{Code}\)

/* Clearink */

#include <cstdio>

inline void wint ( int x ) {
	if ( 9 < x ) wint ( x / 10 );
	putchar ( x % 10 ^ ‘0‘ );
}

const int MAXN = 100;
int N, K, M, f[MAXN + 1][MAXN * ( MAXN / 2 + 1 ) * ( MAXN >> 1 ) / 2 + 5];

inline void addeq ( int& a, const int b ) { ( a += b ) < M ? 0 : a -= M; }

inline void initDP () {
	f[0][0] = 1;
	int sbound = K * ( N / 2 + 1 ) * ( N >> 1 ) >> 1;
	for ( int i = 0; i < N; ++ i ) {
		for ( int j = 0, cur; j <= sbound; ++ j ) {
			if ( !( cur = f[i][j] ) ) continue;
			for ( int k = 0, s = j; k <= K && s <= sbound; ++ k, s += i + 1 ) {
				addeq ( f[i + 1][s], cur );
			}
		}
	}
}

inline int solve ( const int x ) {
	// k[x-1]+2k[x-2]+...+(x-1)k[1] = k[x+1]+2k[x+2]+...+(n-x)k[n].
	int sbound = x - 1 < N - x ? x - 1 : N - x, ret = 0;
	sbound = K * sbound * ( sbound + 1 ) >> 1;
	for ( int s = 0; s <= sbound; ++ s ) {
		addeq ( ret, 1ll * f[x - 1][s] * f[N - x][s] % M );
	}
	return ( ret * ( K + 1ll ) % M + M - 1 ) % M;
}

int main () {
	scanf ( "%d %d %d", &N, &K, &M );
	initDP ();
	for ( int i = 1; i <= N; ++ i ) {
		wint ( solve ( i ) );
		putchar ( ‘\n‘ );
	}
	return 0;
}

Solution -「ARC 104D」Multiset Mean

原文:https://www.cnblogs.com/rainybunny/p/13817640.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!