题目链接:https://ac.nowcoder.com/acm/problem/200214
描述
有n堆石子,第1,2,3...i堆分别为a1,a2,a3...ai个,能通过m次搬运来搬运所有石子,同时只能搬运其中一堆的一些石子,每次搬运会产生搬运石子数量平方的负担,q次询问x v会将第x堆石子变成v个,每次询问完输出最小负担。
思路
如何去操作呢?
\\\\\\\题目数据范围并不是很大,可以在线段树上动态规划去维护这样一个dp数组,第一维代表树的结点,表示区间上通过i次搬运的最优解,每次递归到某个结点时时从1到m去枚举所有可能的次数,通过左儿子和右儿子相加取最小值来更新dp数组 注意每次更新都要将结点上的数初始化为无穷。
最后的dp[1][m]就代表线段树结点1在搬运次数m下的解,也就是整个区间的最优解
mem(dp[node],0x3f);
for(int i=1;i<=m;i++){
for(int j=1;j+i<=m;j++){
dp[node][i+j]=min(dp[l_node][i]+dp[r_node][j],dp[node][i+j]);
}
}那么如何求一堆a个石子,通过m次搬运的最小负担呢?
我们可以发现将a个石子均分成m次搬,多了几份就在多少份上加1 ,这种情况下的负担最小,我们很容易就能求出它
eg:17个石子,5次搬运
3 3 3 3 3 多了两个->3 3 3 4 4;
#include <bits/stdc++.h>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
#define sc(x) scanf("%lld", &(x))
#define pr(x) printf("%lld\n", (x))
#define mem(a, b) memset(a, b, sizeof(a))
#define ios ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
#define int long long
const long long N = 1e6 + 7;
const double eps = 1e-6;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const long long mod = 1e9 + 7;
const int dir[][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0},
{1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const ll inf_ll = 0x3f3f3f3f3f3f3f3f;
#define mid (l+r>>1)
#define l_node node*2
#define r_node node*2+1
int m,n,k;
int a[407];
int dp[1628][407];
void add_up(int node){
mem(dp[node],0x3f);
for(int i=1;i<=m;i++){
for(int j=1;j+i<=m;j++){
dp[node][i+j]=min(dp[l_node][i]+dp[r_node][j],dp[node][i+j]);
}
}
}
int cal(int a,int n){//a个 搬n次花费最小;
return (n-a%n)*(a/n)*(a/n)+((a/n)+1)*((a/n)+1)*(a%n);
}
void updata(int node,int l,int r,int num){
if(l==r){
for(int i=1;i<=m;i++){
dp[node][i]=cal(a[l],i);
}
return ;
}
if(num<=mid)updata(l_node,l,mid,num);
else updata(r_node,mid+1,r,num);
add_up(node);
}
void build(int node,int l,int r){
if(l==r){
for(int i=1;i<=m;i++){
dp[node][i]=cal(a[l],i);
}
return ;
}
build(l_node,l,mid);
build(r_node,mid+1,r);
add_up(node);
}
signed main() {
ios;
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
build(1,1,n);
cin>>k;
while(k--){
int pl,num;cin>>pl>>num;
a[pl]=num;
updata(1,1,n,pl);
cout<<dp[1][m]<<endl;
}
}
京公网安备 11010502036488号