ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ACG054 B - Greedy Division

2021-06-29 19:00:45  阅读:229  来源: 互联网

标签:Division 题目 int ll Greedy sumw 橙子 ACG054 define


目录

题目

https://atcoder.jp/contests/agc054/tasks/agc054_b

思路

怎么看,这题应该要DP,但是描述一个状态是很大问题:你怎么知道选了哪些橙子(共有\(2^{100}\)种情况)?

经过一番漫长的思考后,师父,我悟了!

其实,并不用描述选了哪些橙子,题目的关键就在排列\(P\)和那两人拿橘子的顺序是一一对应的,比如说,Takahashi 依次取了1,5,2号橙子,Aoki依次取了4,3号橙子,那么,有且仅有一个\(P\)和这种情况对应,且该\(P\)只对应这种情况(用心体会下)

这样,问题就简单多了,设\(f_i\)表示拿了\(i\)个橙子,且它们的重量和恰好等于所有橙子重量和的一半,的方案数.答案就应该是(别忘了取模):

\[ans=\sum^n_{i=1}f_i\cdot i!\cdot (n-i)! \]

\(i!\)是其中一个人拿橙子的顺序的方案数,\((n-i)!\)就是另一个人拿橙子的顺序的方案数

如何得到\(f\)?

DP:\(f_{i,j}\)表示拿了\(i\)个橙子,总重量为\(j\)的方案数,过程有点像背包问题,应该都会了吧

代码

#include <iostream>
#include <cstdio>
using namespace std;
#define N 110
#define ll long long
#define mod 998244353ll
ll f[N][10010];
ll n , w[N] , sumw;
ll fac[N];

int main() {
	fac[0] = 1;
	for(int i = 1 ; i <= 100 ; i++)
		fac[i] = fac[i - 1] * i % mod;
	
	cin >> n;
	for(int i = 1 ; i <= n ; i++) {
		cin >> w[i];
		sumw += w[i];
	}
	if(sumw % 2 == 1) {
		cout << 0;
		return 0;
	}
	
	f[0][0] = 1;
	for(int i = 1 ; i <= n ; i++)//枚举第i个橙子
		for(int j = n ; j >= 0 ; j--)//一共j个橙子(除了i),注意倒叙枚举
			for(int k = sumw ; k >= 0 ; k--)//重量(除了i)
				f[j + 1][k + w[i]] += f[j][k],
				f[j + 1][k + w[i]] %= mod;
	
	ll ans = 0;
	for(int i = 1 ; i <= n ; i++)//求答案
		ans = (ans + fac[i] * fac[n - i] % mod * f[i][sumw / 2] % mod) % mod;
	
	cout << ans << endl;
	return 0;
}

标签:Division,题目,int,ll,Greedy,sumw,橙子,ACG054,define
来源: https://www.cnblogs.com/dream1024/p/14951532.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有