刚打完的icpc济南站的C题 Optimal Strategy 比赛时没A出来,思路在比赛时是想对了.但还在想是个dp题,推式子题还是模拟题哈哈.好菜啊.
一般这种大数取模的就得推式子,找规律啥的.今天补了c题,题面如下
(一)题目大意
输入n,再输入n个数.E和M轮流取一个数使各自取到的数字总和最大,E和M都足够聪明.问取数的过程有几种.
(二)思路分析
要让和最大,自然想到每个数都不能太小.若直接贪心每次双方都取最大第一个样例都解释不通.
再模拟样例二发现暗示比较明显,每个数都出现偶数次,样例三便是奇偶出现次数都有.
开一个桶数组c存每个数字的出现次数,则第 i 个数出现 c[i] 次
对于出现奇数次的数,先手取走最大的一个数,后手取走次大的出现的奇数次的数(若上一步先手将最大数取完则后手取走当前最大的出现奇数次的数) 进行完上述操作则提取出各个不相同的数,而这些数对于最后结果无影响.剩下的出现奇数次的数转为出现偶数次
对于出现偶数次的数,双方轮流从大到小拿,一方拿走一个另一方会立刻拿走相同的数.取当前数时有c[i]/2种方案.
从小到大考察每一个数的出现次数,当前数的可选方案数为c[i]/2.比当前数小的数的出现次数和sum可直接作为总和选取.
大数一定可在小数之前选取,故每个数的方案为C(c[i]/2+sum,c[i]/2).
每个数内部排列方案数为 c[i]!
最终结果如下
本题相比推理,更侧重过程的理解和模拟,结合实际去考虑
(三)AC代码
求阶乘可参见下面f[]数组的方法,我直接写的jiecheng函数超时了
处理组合数时如下直接求
**#include#include #include #include #include #include #include using namespace std; typedef long long ll; const int N = 1e6+10; const int mod = 998244353; ll c[N],a[N]; int maxx; ll sum = 0; ll f[N], unf[N]; //ll jiecheng(ll a){ // ll ans = 1; // for(int i=1;i<=a;i++){ // ans = ans * i % mod; //别忘取模%mod,否则 // } // return ans; //} ll zuhe(ll a,ll b){ return (ll)f[a] * unf[b] % mod * unf[a - b] % mod; } int main(){ //下面为求阶乘预处理的方法,速度快,否则jiecheng函数超时 unf[0] = unf[1] = f[0] = 1; for (int i = 1; i < N; i ++) f[i] = (ll) f[i - 1] * i % mod; for (int i = 2; i < N; i ++) unf[i] = (ll)(mod - mod / i) * unf[mod % i] % mod; for (int i = 1; i < N; i ++) unf[i] = (ll) unf[i - 1] * unf[i] % mod; ll res = 1; int n; cin>>n; for(int i=0;i >x; c[x]++; if(maxx < x){ //输入最大数 maxx = x; } // cout<



