【2019 Multi-University Training Contest 9 1006/ HDU 6685】Rikka with Coin

原题传送门

Problem Description

Rikka hates coins, and she used to never carry any coins with her. These days, Rikka is doing her summer internship abroad. Without mobile payment, Rikka has to face strange prices of commodities, and as a result of always using paper currency, she has to face mountainous coins on here table.
In the local currency system, there are 4 kinds of coins: 10 cents, 20 cents, 50 cents and 1 dollar. Up to now, Rikka has gained at least 10100 coins for each kind.
Now, Rikka is going to have dinner in the canteen, and she decides to pay the bill only with coins. There are n different combos in the canteen and the price of the i th is wi cents. Rikka would like to choose one combo as dinner but she has not decided to choose which one yet. Therefore, she wants to take some coins so that whichever she chooses, she can always pay the bill without receiving any change.
Since Rikka hates coins, she wants to carry as few coins as possible with her. As it is generally known that Rikka is not good at math, she wants you to help her make the decision.

Input

The first line of the input contains a single integer T (1≤ T ≤500), the number of test cases.
For each test case, the first line contains a single integer n(1≤ n ≤100), the number of combos sold in the canteen.
The second line contains n positive integers w1 ,…, wn (1≤ wi ≤109), which represents the prices.

Output

For each test case, output a single line with a single integer which represents the minimum number of coins. If there is no valid solution, output −1.

Sample Input

3
5
10 20 30 40 50
5
100 200 300 400 500
1
1

Sample Output

3
5
-1

题目大意

T组数据。n个菜品,第i个菜品的价格为 wi,求能够买任何一样菜品所需的最少硬币数(仅有10,20,50 ,100面额的硬币)题目真好懂ifelseifelse写的真自闭

思路

1.个位不为0的话 输出 -1
2.价格的百位及以上使用100面值的硬币支付
3.注意 所需的面额10~50的硬币可能会凑成100以上 需要减去100面额的硬币
4.反正就n就100嘛 反正10最多1个 20最多4个 50最多1个 那就快乐暴力hhhhhhhhhhh
我才不会承认我看不懂标程(逃

样例解释


5
10 20 30 40 50
5
100 200 300 400 500

为例:
In the first test case, one optimal solution is to bring one coin of 10 cents and two coins of 20 cents.
In the second test case, one optimal solution is to bring 5 coins of one dollar.

Code
#include<bits/stdc++.h>
#define O_O ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;
const int maxn = 200;
ll w[maxn];

int main() {
	O_O;
	int T;
	cin >> T;
	while (T--) {
		int n,flag=0;
		cin >> n;
		for (int i = 1; i <= n; i++) {
			cin >> w[i];
			if (w[i] % 10 != 0) flag = 1;   //判断个位
		}
		if (flag) { cout << "-1\n"; continue; }

		ll f[4] = { 0 };   //sum10 sum20 sum50 sum100
		bool vis[maxn] = { 0 };   //标记数字是否被覆盖
		int money[3] = { 10,20,50 };
		ll ans = INT_MAX;   //最小张数
		
		for (f[0] = 0; f[0] <= 1; f[0]++) {   //枚举10美分的可能张数(如果两张的话可以用20代替 所以最大为1
			for (f[1] = 0; f[1]<= 4; f[1]++) {   //枚举20美分的可能张数( 20 40 60 80特例 所以最大是4
				for (f[2] = 0; f[2] <= 1; f[2]++) {   //枚举50美分的可能张数(两张则可用100代替 所以最大为1
					memset(vis, 0, sizeof(vis));   //每种情况重新标记
					vis[0] = 1;   //总和为0注定存在

					//↓标记能够组成的数
					for (ll i = 0; i <= 2; i++)   //枚举钱的种类
						for (ll j = 1; j <= f[i]; j++)   //枚举钱的张数
							for (ll k = maxn - 1; k >= money[i]; k--)   //枚举金额
								if (vis[k] || vis[k - money[i]]) vis[k] = 1;		
								// ↑ 如果k-money[i]存在的话说明加上当前的money[i]可以组成为k 所以k存在

					ll res = 0;		//所需面额100的个数
					for (ll i = 1; i <= n; i++) {
						if (w[i] < 100 && !vis[w[i]]) res = INT_MAX;
						// ↑ 当w[i]小于100且上述枚举的张数并不能构成它时,res不存在
						else {
							if (vis[(w[i] % 100) + 100]) res = max(res, (w[i] - ((w[i] % 100) + 100)) / 100);		     
							//判断前面的张数组成是否能够组成>100 如果> 那就可以少用一个100啦
							else {
								if (vis[w[i] % 100]) res = max(res, w[i] / 100);   //终于正常了
								else res = INT_MAX;   //这你要是还是else就是你的不对了
							}
						}
					}
					ans = min(ans, res + f[0] + f[1] + f[2]);   //取每次最小
				}
			}
		}
		if (ans == INT_MAX) cout << "-1\n";
		else cout << ans << "\n";
	}
	return 0;
}

↑ 虽然不是本蒟蒻自己写的代码但是我会写她了所以我还是想贴
↓ 虽然没有看懂大佬写的标程,但是我还是想贴 [假装理直气壮]

标程
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int N=1100,lim=40;
int A[N],n,ans=1e9,pd[lim+10];
const int w[4]={1,2,5,10};
const int num[4]={1,3,1,3};
void put(int k){
	for (int i=lim;i>=k;i--) pd[i]|=pd[i-k];
}
int calc(){
	int w=0;
	for (int i=1;i<=n;i++){
		int k=A[i]%10;
		int num=1e9;
		while (k<=lim&&k<=A[i]){
			if (pd[k]) num=min(num,(A[i]-k)/10);
			k+=10;
		}
		w=max(w,num);
	}
	return w;
}
void getans(int k,int tot){
	if (k==4){
		ans=min(ans,calc()+tot); return;
	}
	int back[lim+10]; memcpy(back,pd,sizeof pd);
	for (int i=0;i<=num[k];i++){
		getans(k+1,tot+i); put(w[k]);
	}
	memcpy(pd,back,sizeof back);
}
void solve(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++){
		scanf("%d",&A[i]);
	}
	for (int i=1;i<=n;i++){
		if (A[i]%10){
			printf("-1\n"); return;
		}
		A[i]/=10;
	}
	ans=1e9; memset(pd,0x00,sizeof pd); pd[0]=1;
	getans(0,0);
	printf("%d\n",ans);
}
int main(){
	int t; scanf("%d",&t);
	for (;t;t--) solve();
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值