题目链接: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; } }