D. Smithing Skill
题意:n个武器和m种锻造锭,每个武器 每次锻造花费a[i]个锭 熔断获得b[i]个锭,锻造和熔断都能获得1点经验,所以锻造并熔断是获得经验的最好做法,m种锭,每个锭有 c[i]个,问你能获得的最大经验值。
算法:动态规划 预处理
思路:根据题目要求,先处理出可以锻造的武器的每个所需值也就是a[i] 和每次锻造并熔断的损耗值也就是a[i]-b[i],记录每个损耗值下最低的所需值,抛弃相同损耗值下更高的损耗值和损耗值更高且所需值也高的武器,预处理出1到1e6的每个武器可以得到的最大经验值,使用动态规划递推,状态转移方程为 dp[i]=dp[i-当前可行武器的最大损耗值]+2 预处理出所有1到1e6的锭下获得的最大经验值,后续判断每个武器是否大于1e6若大于则先使用最小损耗值的武器将其降到1e6以下,若不大于1e6则答案就是dp[c[i]]。
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int Q = 1e6 + 9;
ll a[Q],b[Q],c[Q],dp[Q],tp[Q];
map<ll,ll> mp;
set<ll> s;
struct cmp
{
bool operator()(const pair<ll,ll> l,const pair<ll,ll> r) const {
return l.first<r.first;
}
};
set<pair<ll,ll>,cmp> st;
void solve(){
ll n,m;cin>>n>>m;
for (ll i = 1; i <= n; i++) cin>>a[i];
for (ll i = 1; i <= n; i++) cin>>b[i];
for (ll i = 1; i <= m; i++) cin>>c[i];
for (ll i = 1; i <= n; i++) {
ll lose=a[i]-b[i];
if(mp[lose]==0){
mp[lose]=a[i];
}else{
mp[lose]=min(mp[lose],a[i]);
}
}
vector<set<pair<ll,ll>>::iterator> de;
ll now=1e18;
for(auto [o,p]:mp) st.insert({o,p});
for(auto it=st.begin();it!=st.end();it++){
if((*it).second>=now){
de.push_back(it);
}else{
now=(*it).second;
}
}
for(auto i:de){
st.erase(i);
}
for(auto [o,p]:st){
tp[p]=o;
s.insert(p);
}
set<ll>::iterator it=s.begin(),it2;
it2=it;it2++;
for (ll i = 1; i <= 1e6; i++)
{
if(it2!=s.end() and i>=*it2) it++,it2++;
if(i>=*it){
dp[i]=dp[i-tp[*it]]+2;
}else{
dp[i]=dp[i-1];
}
}
set<ll>::iterator ti=s.end();
ti--;
ll ans=0;
for (ll i = 1; i <= m; i++)
{
if(c[i]>=1e6){
ll op=((c[i]-1e6)/tp[*ti]+1);
ans+=op*2;
c[i]-=op*(tp[*ti]);
}
ans+=dp[c[i]];
}
cout<<ans;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
ll _ = 1;//cin>>_;
while(_--){
solve();
}
return 0;
}