小度新聘请了一名员工牛牛, 每个月小度需要给牛牛至少发放m元工资(给牛牛发放的工资可以等于m元或者大于m元, 不能低于m)。
小度有一些钞票资金, 一共有n种不同的面额, 对于面额为的钞票, 小度有张, 并且每一个钞票面额都能整除所有比它大的面额, 并且每一张钞票不能找零。
小度想知道这部分资金最多能牛牛发放多少个月的工资?
包括n+1行,第一行包括两个正整数。
接下来的n行, 每行两个正整数, 即面额和该面额所拥有的钞票数量。
一个整数,表示最多能支付多少个月工资。
3 51 100 1 50 4 1 2
4
注意钱不能找零,所以:
100能支付一个月工资
50+1,50+1能支付两个月工资
50+50能支付一个月工资
即最多能支付四个月的工资。
import java.util.ArrayList; import java.util.List; import java.util.Scanner; class Money { int value; int nums; public Money(int value, int nums) { this.value = value; this.nums = nums; } } public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int m = sc.nextInt(); List<Money> list = new ArrayList<>(); for (int i = 0; i < n; i++) { int a = sc.nextInt(); int b = sc.nextInt(); list.add(new Money(a, b)); } list.sort((a, b) -> b.value - a.value); int ans = 0; //先把大的直接发出去 for (Money money : list) { if (money.value >= m) { ans += money.nums; money.nums = 0; } else break; } //然后开始车轮战,每一趟while发出一个月工资 while (true) { int needToPay = m; //先从大面额开始涮一轮,在不超m的情况下,尽可能地拿大面额 for (Money money : list) { if (money.nums == 0) continue; int needNum = needToPay / money.value; needNum = Math.min(needNum, money.nums);//最多取完,不能超了。 money.nums -= needNum; needToPay -= needNum * money.value; } //刚好凑成了就结束这一趟 if (needToPay <= 0) { ans++; continue; } //再从小面额开始补(此时所有面额都已大于needToPay) for (int i = list.size() - 1; i >= 0; i--) { Money money = list.get(i); if (money.nums == 0) continue; money.nums--; needToPay -= money.value; ans++; break; } if (needToPay > 0) break; } System.out.println(ans); } }
import java.util.*; import java.io.*; class Money{ public int value;//钞票面额 public int num;//该面额钞票的数量 } // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) throws IOException{ BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String[] s = in.readLine().split(" "); int n = Integer.parseInt(s[0]), m = Integer.parseInt(s[1]); Money[] a = new Money[n]; for(int i = 0; i < n; i++){ s = in.readLine().split(" "); a[i] = new Money(); a[i].value = Integer.parseInt(s[0]); a[i].num = Integer.parseInt(s[1]); } Arrays.sort(a, new Comparator<Money>(){//将钞票按从大到小排列 public int compare(Money a1, Money a2){ return a2.value - a1.value; } }); int large = 0;//用于后续直接从面额小于工资的钞票开始遍历 int month = 0;//能发工资的月份 //将面额大于等于工资的钞票全部取出直接发工资 while(large < n && a[large].value >= m){ month += a[large].num; a[large].num = 0; large++; } //处理面额小于工资的钞票 while(true){ int npay = m;//记录一个月还需要支付多少工资 //先从面额大的开始取,取到刚好不超过工资数量 for(int i = large; i < n; i++){ if(a[i].num == 0) continue; int pNum = npay / a[i].value;//记录某个面额钞票能够补的数量 pNum = Math.min(pNum, a[i].num);//不能超过钞票剩余数量 npay -= pNum * a[i].value; a[i].num -= pNum; if(npay <= 0) break;//刚好取到工资的数量,直接跳出循环 } //如果刚好取到了工资的数量,就直接发工资 if(npay <= 0){ month++; continue; } //再从面额小的开始补工资 for(int i = n-1; i >= large; i--){ if(a[i].num == 0) continue; while(npay > 0 && a[i].num > 0){ npay -= a[i].value; a[i].num--; } if(npay <= 0){//工资补够了,跳出循环 month++; break; } } if(npay > 0) break;//钞票都补完了还没补够,没救了 } System.out.println(month); } }
import java.util.*; class Money { public int mianZhi; public int num; } public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int numOfMoney = in.nextInt(); // 面值的种类 int salary = in.nextInt(); // 每月的工资 Money[] money = new Money[numOfMoney]; for (int i = 0; i < money.length; ++i) { money[i] = new Money(); money[i].mianZhi = in.nextInt(); money[i].num = in.nextInt(); } Arrays.sort(money, new Comparator<Money>() { @Override public int compare(Money m1, Money m2) { // 降序 return m2.mianZhi - m1.mianZhi; } }); // 对Money数组按照mianZhi降序排序 int month = 0; // 因为不能找零,所以先把面值大于salary的钞票用完 int moreThanSalary = 0; while (moreThanSalary < money.length && money[moreThanSalary].mianZhi >= salary) // 防止下标越界!!! { month += money[moreThanSalary].num; money[moreThanSalary].num = 0; ++moreThanSalary; } // 然后用剩下的钞票开始组合(贪心),此时moreThanSalary就是面值小于salary的钞票的起始下标 while (true) { int remain = salary; // remain表示剩余的应发工资 for (int j = moreThanSalary; j < money.length; ++j) // 贪心一趟,结束后remain>=0 { while (money[j].mianZhi <= remain && money[j].num > 0) // 当前面值小于remain,就使劲用 { remain -= money[j].mianZhi; --money[j].num; } } for (int j = money.length - 1; j >= moreThanSalary && remain > 0; --j) // 若remain>0,从小面值到大面值再凑 { if (money[j].num > 0) { remain -= money[j].mianZhi; --money[j].num; } } if (remain > 0) // remain仍然大于0,说明剩余的钞票已经不够用,结束循环 { break; } else // 多发一个月的工资 { ++month; } } System.out.println(month); } }
import java.util.*; class Money { int value; int nums; public Money(int value, int nums) { this.value = value; this.nums = nums; } } public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n ,m; n = sc.nextInt(); m = sc.nextInt(); List<Money> list = new ArrayList<>(); for (int i = 0; i < n; i++) { int value = sc.nextInt(); int nums = sc.nextInt(); Money money = new Money(value,nums); list.add(money); } Collections.sort(list,(o1,o2) -> o2.value- o1.value); int ans = 0; // 第一种情况把大于工资的花完 for (int i = 0; i < list.size(); i++) { //先把大钱用完 Money money = list.get(i); if (money.value < m) break; ans += money.nums; money.nums = 0; } while (true){ int res = m; for (int i = 0; i < list.size(); i++) { Money tmp = list.get(i); if (tmp.nums == 0) continue; int need = res / tmp.value; if (need > tmp.nums) need = tmp.nums; res = res - need * tmp.value; tmp.nums -= need; } // 到这里所有可用的面额都大于 res ,从小开始补余额 for (int i = list.size() -1; i >= 0 && res>0; i--) { Money tmp = list.get(i); if (tmp.nums == 0) continue; int need = Math.max(res / tmp.value ,1 ); need = Math.min(need, tmp.nums); tmp.nums = tmp.nums - need; res -= need * tmp.value; } if (res >0) break; ans++; } // for (int i = 0; i < list.size(); i++) { // System.out.println("value :"+list.get(i).value + " nums:"+list.get(i).nums); // } System.out.println(ans); } }
#include <bits/stdc++.h> typedef std::pair<int, int> PAII; using namespace std; struct Money { long long x; int y; bool operator<(Money m2) const { return x < m2.x; } }; istream &operator>>(istream &is, Money &money) { is >> money.x >> money.y; return is; } int main() { int n; long long m; cin >> n >> m; long long totalSum = 0L; vector<Money> moneyGroup(n); unordered_map<int,int> modMoney; for (int i = 0; i < n; ++i) { cin >> moneyGroup[i]; totalSum += moneyGroup[i].x * moneyGroup[i].y; } if (totalSum < m) { cout << 0 << endl; } else { sort(moneyGroup.begin(), moneyGroup.end()); long long ans = 0; while (1) { long long rest = m; for (int i = n - 1; i >= 0 && rest > 0; --i) { if (moneyGroup[i].y == 0) continue; // 有个整除关系感觉没用到。 // 先用大钱的思路没错,但是用小钱补的时候,小钱能提供更多的容错率 auto need = rest / moneyGroup[i].x; if (need > moneyGroup[i].y) { need = moneyGroup[i].y - 1; } rest -= need * moneyGroup[i].x; moneyGroup[i].y -= need; } for (int i = 0; i < n && rest > 0; ++i) { if (moneyGroup[i].y == 0) continue; auto need = max((int)(rest / moneyGroup[i].x),1); if (need > moneyGroup[i].y) { need = moneyGroup[i].y; } rest -= need * moneyGroup[i].x; moneyGroup[i].y -= need; } if (rest > 0) break; ++ans; } cout << ans; } }