题目:每次选取连续的若干数字的代价
要求选取虽有数字的最小代价.
思路:基础斜率dp题,题解见http://www.cnblogs.com/kuangbin/archive/2012/08/26/2657650.html
/* * @author: Cwind */ #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-6) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const int maxn=5e5+3000; int n,m; int a[maxn]; int Q[maxn]; int sum[maxn]; int dp[maxn]; int front,back; int get1(int a,int b){ return dp[b]+sq(sum[b])-dp[a]-sq(sum[a]); } int get2(int a,int b){ return 2*(sum[b]-sum[a]); } int main(){ freopen("/home/files/CppFiles/in","r",stdin); //freopen("test.in","r",stdin); //freopen("test.out","w",stdout); while(cin>>n>>m){ front=back=0; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } Q[back++]=0; for(int i=1;i<=n;i++){ while(front+1<back&&get1(Q[front],Q[front+1])<=sum[i]*get2(Q[front],Q[front+1])){ front++; } dp[i]=dp[Q[front]]+sq(sum[i]-sum[Q[front]])+m; while(front+1<back&&get1(Q[back-2],Q[back-1])*get2(Q[back-1],i)>=get1(Q[back-1],i)*get2(Q[back-2],Q[back-1])){ back--; } Q[back++]=i; } printf("%d\n",dp[n]); } return 0; }
时间: 2024-12-19 12:37:30