@noi.ac - [emailprotected] 数数
目录
@[email?protected]求有多少对 1 ~ n 的排列 (a,b) 满足 (m le sum_{i=1}^{n}max(ai,bi))。 两个方案 (a,b) 和 (a′,b′) 不同当且仅当存在 i 使得 (ainot =a′i)或 (binot =b'i)。 input output sample input 对于100%的数据,1≤n≤50,1≤m≤10^9。 @[email?protected]根据我多年 OI 经验,题目短的不是水就是毒瘤。 可以发现 a 中元素与 b 中元素的一一对应的关系确定了 (sum_{i=1}^{n}max(ai,bi))。 另外还可以发现,题目所给的和式其中一个上界为 n*n(可以发现这是一个不是很紧的上界,但足够了)。故当 m > n*n 时直接输出 0 就好了。 我们为了保证 max 函数的唯一性,不妨令 ai >= bi 时 max(ai,bi) = ai;ai < bi 时 max(ai,bi) = bi。 于是我们可以从小到大,考虑每一个数 i 在 a 序列与 b 序列中是否会对答案产生贡献。我们只需要知道在 i 之前有多少数未被配对。 通过分类讨论 a 中的 i 是否有贡献以及 b 中的 i 是否有贡献,得到四类转移。 @accepted [email?protected]#include<cstdio> const int MOD = 998244353; const int MAXN = 50; int dp[MAXN + 5][MAXN + 5][MAXN*MAXN + 5]; int main() { int n,m; scanf("%d%d",&n,&m); if( m > n*n ) { puts("0"); return 0; } int ans = 1; for(int i=1;i<=n;i++) ans = 1LL*i*ans%MOD; dp[0][0][0] = 1; for(int i=1;i<=n;i++) { for(int j=1;j<=i;j++) for(int k=0;k<=n*n;k++) dp[i][j][k] = (dp[i][j][k] + dp[i-1][j-1][k])%MOD; for(int j=0;j<i;j++) for(int k=i;k<=n*n;k++) dp[i][j][k] = (dp[i][j][k] + 1LL*j*dp[i-1][j][k-i]%MOD)%MOD; for(int j=0;j<i;j++) for(int k=i;k<=n*n;k++) dp[i][j][k] = (dp[i][j][k] + 1LL*(j+1)*dp[i-1][j][k-i]%MOD)%MOD; for(int j=0;j<i-1;j++) for(int k=2*i;k<=n*n;k++) dp[i][j][k] = (dp[i][j][k] + 1LL*(j+1)*(j+1)%MOD*dp[i-1][j+1][k-2*i]%MOD)%MOD; } int res = 0; for(int i=m;i<=n*n;i++) res = (res + dp[n][0][i])%MOD; printf("%lldn",1LL*ans*res%MOD); } @[email?protected]就代码而言写起来还是很愉快的,甚至不足 1kb。 然而我当时好像一不小心把 m ≤ …… 看成 m = …… 不过还好最后改过来了,不然就直接炸掉了。。。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |