CF767E-Change-free

CF767E-Change-free

题目大意

你接下来 \(n\) 天回去食堂吃饭,而且现在你已经决定好了吃什么,所以你在接下来的第 \(i\) 天,花费 \(c_i\) 元。

交易时只允许使用 \(1\) 元的硬币和 \(100\) 元的纸币,你初始有 \(m\) 硬币和无限多的纸币。在其中的某些天你可能不够正好支付 \(c_i\) 元,所以会面临找零。但是收银员在找零时会产生不满。如果收银员在第 \(i\) 天找了 \(x\) 纸币和硬币。那么会产生 \(x \cdot w_i\) 点不满。收银员总是尽量用最少的硬币和纸币找零。

你希望使得收银员总不满尽可能小。你需要确认在接下来 \(n\) 天的最小总不满和如何支付的方案。

题解

考虑贪心,现在手上有的硬币如果满足当天所需,则尽可能使用。否则就找到在此之前不满程度最小的一天,来找零。对于被找零的那天,本身花了 \(c_i \% 100\) 元,现在不仅没花,而且获得了 \(100-c_i \% 100\) 元,所以一次找零的贡献是固定的 \(100\) 。因此对于每一天来说都有一个固定的不满,和一样的贡献。所以用优先队列维护不满最小值。每次取最小值即可。

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define umap unordered_map
#define endl '\n'
using namespace std;
using i128 = __int128;
const int mod =1e9+7;
template <typename T>void read(T&x){
    x=0;int f = 1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);
    x*=f;
}
template <typename T>void print(T x) {
     if (x < 0) { putchar('-'); x = -x; }
     if (x > 9) print(x / 10);
     putchar(x % 10 + '0');
}
#define int long long
const int N=500005;
const int M=2000005;
map<int,int> ans;
inline void solve()
{
	ans.clear();
	int n,m;
	cin>>n>>m;
	vector<int> num(n+1);
	for(int i=1;i<=n;i++) 
	{
		cin>>num[i];
	}
	vector<int> w(n+1);
	for(int i=1;i<=n;i++) cin>>w[i];
	priority_queue<pair<int,int> ,vector<pair<int,int>>,greater<pair<int,int>> > q;
	int cost=0;
	for(int i=1;i<=n;i++)
	{
		if(num[i]%100==0) continue;
		q.push({(100-(num[i]%100))*w[i],i});
		if(m<num[i]%100)
		{
			m+=100;
			cost+=q.top().first;
			ans[q.top().second]++;
			q.pop();
		}
		m-=num[i]%100;
//		cout<<m<<endl;
	}
	cout<<cost<<endl;
	for(int i=1;i<=n;i++)
	{
		if(ans[i])
		{
			cout<<num[i]/100+1<<" "<<0<<endl; 
		}
		else
		{
			cout<<num[i]/100<<" "<<num[i]%100<<endl;
		}
	}
}

signed main()
{
	ios;
	int T=1;
//	cin>>T;
	for(;T--;) solve();
	return 0;
}

posted @ 2025-12-01 12:25  NDAKJin  阅读(2)  评论(0)    收藏  举报