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;
}

浙公网安备 33010602011771号