首页 > 其他分享 >LG4026 [SHOI2008]循环的债务 题解

LG4026 [SHOI2008]循环的债务 题解

时间:2022-11-04 15:13:57浏览次数:122  
标签:LG4026 数为 题解 ll 钞票 SHOI2008 include 分配 dp

LG4026 [SHOI2008]循环的债务

给出三个整数 \(x_1,x_2,x_3\)。

\(x_1\) 代表 A 欠 B 的钱数,\(x_2\) 表示 B 欠 C 的钱数,\(x_3\) 表示 C 欠 A 的钱数。

接下来 \(3\) 行,每行包括 \(6\) 个自然数,为

\[\begin{array}{llllll} a_{1} & a_{2} & a_{3} & a_{4} & a_{5} & a_{6} \\ b_{1} & b_{2} & b_{3} & b_{4} & b_{5} & b_{6} \\ c_{1} & c_{2} & c_{3} & c_{4} & c_{5} & c_{6} \end{array} \]

分别表示 A,B,C 三人所拥有的 \(v=\{100,50,20,10,5,1\}\) 元钞票数。

问如果三人的债务可以还清,输出需要交换钞票的最少张数,否则输出 \(\texttt{impossible}\)。

A 目前拥有的钱数为 \(suma=100a_{100}+50a_{50}+20a_{20}+10a_{10}+5a_5+a_1\),B,C 计算同理。

A 还债后的钱数为 \(suma-x_1+x_3\),B 还债后的钱数为 \(sumb-x_2+x_1\),C 还债后的钱数为 \(sumc-x_3+x_2\)。

我们的问题其实可以转化为了为三人分配各种钞票,使得每人每种钞票的分配数量减去原先拥有情况的绝对值之和最小。

定义每种钞票总数为 \(all_i=a_i+b_i+c_i\),设 \(dp_{i,j,k}\) 为考虑前 \(i\) 种钞票,A 已经分配 \(j\) 元,B 分配 \(k\) 元,此时与原先分配情况差的绝对值。假设 A 分配 \(x\) 张此种钞票,B 分配 \(y\) 张此种钞票,则 C 分配到 \(all_i-x-y\) 张。得到转移

\[dp_{i,j,k}\gets dp_{i-1,j-x\times v_i,k-y\times v_i}+|x-a_i|+|y-b_i|+|all_i-x-y-c_i| \]

具体细节见代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;
typedef pair<int,int>ttfa;
inline ll read(){
	ll x=0,f=1;char ch=getchar();
	while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();}
	while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*f;
}
const int N=1003,INF=0x3f3f3f3f;
const int val[7]={0,100,50,20,10,5,1};
int a[7],b[7],c[7],all[7];
int va,vb,vc,suma,sumb,sumc,ha,hb,hc,sum;
int dp[7][N][N];
int main(){
	va=read(),vb=read(),vc=read();
	for(int i=1;i<=6;++i){
		a[i]=read();
		suma+=a[i]*val[i];
	}
	for(int i=1;i<=6;++i){
		b[i]=read();
		sumb+=b[i]*val[i];
	}
	for(int i=1;i<=6;++i){
		c[i]=read();
		sumc+=c[i]*val[i];
	}
	sum=suma+sumb+sumc;
	for(int i=1;i<=6;++i)all[i]=a[i]+b[i]+c[i];
	ha=suma+vc-va,hb=sumb+va-vb,hc=sumc+vb-vc;
	//("%d %d %d\n",ha,hb,hc);
	memset(dp,0x3f,sizeof(dp));
	dp[0][0][0]=0;
	for(int i=1;i<=6;++i){
		for(int j=ha;j>=0;--j){
			for(int k=hb;k>=0;--k){
				if(j+k>sum)continue;
				for(int v1=0;v1<=all[i]&&v1*val[i]<=j;++v1){
					for(int v2=0;v1+v2<=all[i]&&v2*val[i]<=k;++v2){
						dp[i][j][k]=min(dp[i][j][k],dp[i-1][j-v1*val[i]][k-v2*val[i]]+abs(v1-a[i])+abs(v2-b[i])+abs(all[i]-v1-v2-c[i]));
					}
				}
			}
		}
	}
	if(dp[6][ha][hb]<INF)printf("%d\n",dp[6][ha][hb]/2);
	else puts("impossible");
	return 0;
}

标签:LG4026,数为,题解,ll,钞票,SHOI2008,include,分配,dp
From: https://www.cnblogs.com/BigSmall-En/p/16857839.html

相关文章

  • WiredTiger引擎编译 及 LT_PREREQ(2.2.6)问题解决
    近期需要为异构引擎做准备,wiredtiger以其优异的性能(B-tree和LSM-tree都支持)和稳定性(Mongodb的默认存储引擎)被我们备选为异构引擎里的一个子引擎,后续将深入wiredtiger......
  • CF 1749 题解
    比赛链接:https://codeforces.com/contest/1749题解:AB水题//bySkyRainWind#include<cstdio>#include<vector>#include<cstring>#include<iostream>#include......
  • P4774 倚天屠龙传 题解
    其实这道题的主体并不难,主要是细节很多我们可以把题目分成界限分明的两部分,第一部分,屠每条龙所用的剑只和当前拥有的剑有关。于是可以单独开一个数据结构按题目维护。另......
  • 2022 CSP-S题解
    T1:假期计划给定\(n\)个点\(m\)条边的无向图,每个点有一个点权。在图中选\(4\)个不同的点,从\(1\)号点出发完成\(5\)段行程:\(1\toA\toB\toC\toD\to1\),每......
  • JOIOI の塔 题解
    题目传送门洛谷上竟然还没有题解...题目分析简单贪心题。考虑倒过来寻找。显然,如果一个J想要配成一座塔,那么必须要找一个OI。O更简单,就是直接找到一个I放上去就......
  • CF912D 小鱼仔 题解
    这是一个很邪门的贪心考虑到最终答案是每个正方形的贡献除以总的正方形个数,而正方形个数容易计算,那么只需最大化贡献。从题面给出的图易得每个点被覆盖的次数是一定的,我......
  • ckeditor粘贴word图片问题解决
    ​ 自动导入Word图片,或者粘贴Word内容时自动上传所有的图片,并且最终保留Word样式,这应该是Web编辑器里面最基本的一个需求功能了。一般情况下我们将Word内容粘贴到Web编辑......
  • [ARC087F] Squirrel Migration 题解
    [ARC087F]SquirrelMigration给你一个\(n\)个节点的树,求一个\(1\simn\)的排列\((p_1,p_2,\dotsp_n)\),使得\(\sumdist(i,p_i)\)最大。求这样的排列个数。答案......
  • 【题解】P8818 [CSP-S 2022] 策略游戏
    【题解】P8818[CSP-S2022]策略游戏这道题应该是CSP-S2022所有题里面最简单的一道了,主要是有点套路,刨开套路,其实就是个静态维护区间最大最小值的板子。作为一名场外......
  • [题解] HDU7060 Separated Number 思路整理
    题目链接HDU7060SeparatedNumber题目大意给一个\(n\)位数,把该数字分成\(k\)段,每种方案的贡献为其分割出的段的数字之和。求所有分法的贡献之和(对\(998244353\)......