题意很明确,n个值,两个人轮流取,问有多少种可能,然后取模。
这个题意看看样例应该很好理解
首先统计一下每个数的个数,然后顺序排好,就没有问题了。
我推出的第一条性质是如果存在一个奇数个的大数,那么它一定会比这个数下面的数先被取走,偶数个数的大数,乃至偶数个的任何数都没有这个性质。
由此再考虑偶数个的数字,我们发现偶数取的规律十分随意,但是呢,有一个很抽象的性质,对于后手来说,先手如果取了一个偶数个数的数,那么我作为后手一定会去选择一个比你大或者等于你的偶数的数,这里的前提是没有个数的数了,因为前面说了,奇数一定在此之前就被取走了;(感性理解的话,这些数都是成对的,你拿啥我拿啥,甚至我拿的比你还大,那么两个人都用此策略,是完全不会影响答案的)理解之后发现规律,把对相同的偶数看作括号,则上面和下面的不能相交,也就是如果有3 ,3 ,4 ,4 四个数字,我如果拿3,你拿4我肯定不能拿3 了,这样就是相交,3,4,4,3就是包含,就是不相交的情况。其次呢,对于成对的大数,要么与小数并列,要么被小数的括号包含起来。
考虑这样的状态数,从小到大遍历,把成对的大数一起放,下面的小数是可以放进小数中间的,也就是放4,4 的时候,可以放成3,3,4,4或者4,4,3,3或者3,4 ,4,3;但是大的是在一起的,小数是可以分开的。
所以这样的话,我们考虑每个数往里放的贡献,累乘起来就好了。
这里挂出来官方题解:
首先ci!是肯定大家都知道的,然后每次后面的组合公式的意思是,对于每次往里放大数的时候,成对的放,就有ci/2取整对,然后考虑到放完之后会有
种状态,那么从中选出ci/2种作为放入的序列,然后再乘上阶乘就是每次的答案,累乘起来就是结果。
#include#define ll long long const ll mod = 998244353; const ll p = 998244353; const ll N = 2e6 + 1000; using namespace std; ll arr[N]; ll ux[N]; vector st; typedef long long LL; LL n, m; LL quick_mod(LL a, LL b) { LL ans = 1; a %= p; while (b) { if (b & 1) { ans = ans * a % p; b--; } b >>= 1; a = a * a % p; } return ans; } LL C(LL n, LL m) { if (m > n) return 0; LL ans = 1; for (int i = 1; i <= m; i++) { LL a = (n + i - m) % p; LL b = i % p; ans = ans * (a * quick_mod(b, p - 2) % p) % p; } return ans; } LL Lucas(LL n, LL m) { if (m == 0) return 1; return C(n % p, m % p) * Lucas(n / p, m / p) % p; } inline void solve() { ux[0] = 1; for (ll i = 1; i <= 1000009; i++) { ux[i] = ux[i - 1] * i; ux[i] %= mod; } ll n; scanf("%lld", &n); for (ll i = 0; i < n; i++) { scanf("%lld", &arr[i]); } sort(arr, arr + n); ll cnt = 1; for (ll i = 1; i < n; i++) { if (arr[i] == arr[i - 1]) cnt++; else st.push_back(cnt), cnt = 1; } st.push_back(cnt); ll t = 0, ans = 1; for (ll i = 0; i < st.size(); i++) { int uu=st[i]/2; ans*=Lucas(uu+t,uu); ans%=mod; ans*=ux[st[i]];ans%=mod; t+=st[i]; } printf("%lldn", ans % mod); } int main() { solve(); return 0; }



