zoukankan      html  css  js  c++  java
  • ACG054 B

    题目

    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_icdot 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;
    }
    
  • 相关阅读:
    centos6升级内核
    centos7启动盘制作
    sed匹配字符串并将匹配行的后几行注释
    cmd下调用xshell登录linux服务器
    centos清除历史命令
    yum错误Cannot retrieve metalink for repository: epel/x86_6
    ansible-playbook
    jdk升级到1.8
    shell瞎记录
    shell 循环
  • 原文地址:https://www.cnblogs.com/dream1024/p/14951532.html
Copyright © 2011-2022 走看看