The 2021 Shanghai Collegiate D. Zztrans 的班级合照(清新小dp)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了The 2021 Shanghai Collegiate D. Zztrans 的班级合照(清新小dp)相关的知识,希望对你有一定的参考价值。
题意
n n n个数字(彼此不同,就算大小相等也不同)
分成大小为 n 2 \\frac{n}{2} 2n的两个不递减序列,且第一个序列的每个位置都不小于第二个序列的对应位置
求方案数
我们先把数组
a
a
a排个序,不排序怎么做
T 1 T1 T1
如果没有两个序列对应位置的大小关系限制,那么很好做
只需要考虑 a i a_i ai是放在第一个序列还是放在第二个序列即可
这样我们定义 f [ i ] [ j ] f[i][j] f[i][j]表示前 i i i个数,第二个序列放了 j j j个第一个序列放了 i − j i-j i−j个的方案
但是又考虑到数字相同时,放的顺序可以任意
所以我们直接把相同的数字 x x x缩成一个点,设共有 t t t个 x x x
枚举分配给第一个序列 q q q个 x x x,分配给第二个序列 t − q t-q t−q个 x x x
这样 d p dp dp就没有考虑顺序,所以最后乘以一个 t ! t! t!即可
T 2 T2 T2
现在要求第一个序列的对应位置不小于第二个序列,也就是任意时刻 j > = i − j j>=i-j j>=i−j
这个限制比较巧妙,利用后面加进来的数字更大的特性完美满足了这个限制
d p dp dp数组的含义不变,但是所有 j < i − j j<i-j j<i−j的状态都变成不合法状态
其实仔细观察转移方程,可以用数据结构优化区间和做到 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
int f[5009][5009],n,ans,fac[5009],a[5009],pos[5009];
void upd(int &x,int y){ x = ( x+y )%mod; }
vector<int>vec;
signed main()
{
fac[0] = 1;
for(int i=1;i<=5000;i++) fac[i] = fac[i-1]*i%mod;
cin >> n;
for(int i=1;i<=n;i++) cin >> a[i], pos[a[i]]++;
sort( a+1,a+1+n );
a[0] = a[1]; a[n+1] = -1;
int temp = 0;
for(int i=1;i<=n+1;i++)
{
if( a[i]==a[i-1] ) temp++;
else
{
vec.push_back( temp );
temp = 1;
}
}
f[0][0] = 1;
int pre = 0;
for(auto v:vec )
{
pre += v;
for(int j=min(pre,n/2);j>=pre-j;j--)
for(int q=0;q<=v && q<=j ;q++)
upd( f[pre][j],f[pre-v][j-q] );
}
int ans = f[n][n/2];
for(int i=1;i<=n;i++) ans = ans*fac[pos[i]]%mod;
cout << ans;
}
以上是关于The 2021 Shanghai Collegiate D. Zztrans 的班级合照(清新小dp)的主要内容,如果未能解决你的问题,请参考以下文章
The 2019 ICPC Asia Shanghai Regional Contest
The Preliminary Contest for ICPC Asia Shanghai 2019
The Preliminary Contest for ICPC Asia Shanghai 2019
Digit sum-----The Preliminary Contest for ICPC Asia Shanghai 2019
The Preliminary Contest for ICPC Asia Shanghai 2019 L. Digit sum
The Preliminary Contest for ICPC Asia Shanghai 2019 J. Stone game