「QFOI R2」钟声远带斜阳
题目描述
注意:本题中的所有数列下标从 \(0\) 开始。
小 R 是一个可爱的女孩子,她喜欢研究无穷数列。
她称一个无穷数列 \(b\) 是美妙的,当且仅当存在自然数 \(k_0\),使得对于所有 \(k\ge k_0\),都满足 \(b\) 中下标在区间 \([k_0,k]\) 内的所有数的和非负(即 \(\sum_{i=k_0}^kb_i\ge 0\))。例如,数列 \(\alpha_i=i-5\) 是美妙的,取 \(k_0=5\) 符合要求;但 \(\beta_i=-i\) 不是美妙的。
她目前只有一个长度为 \(n\) 的有穷数列 \(a\),可以进行任意次以下三种操作:
- 花费 \(p\) 的代价,选择一个整数 \(i\)(\(0\le i < n\)),将 \(a_i\) 增加一。
- 花费 \(q\) 的代价,选择一个整数 \(i\)(\(0\le i < n\)),将 \(a_i\) 删除,同时更新 \(n\) 为新的数列长度。不能将数列删空。
- 花费 \(r\) 的代价,选择两个整数 \(i,j\)(\(0\le i < j < n\)),交换 \(a_i\) 与 \(a_j\)。
她希望在若干次操作后,用无限个有穷数列 \(a\) 依次相接得到无穷数列 \(b\)(即 \(b_i=a_{i\bmod n}\)),使得 \(b\) 是美妙的。请你求出最小的代价。
输入格式
第一行四个整数 \(n,p,q,r\)。
第二行 \(n\) 个整数,表示数列 \(a\)。
输出格式
一行,一个整数,表示最小代价。
样例 #1
样例输入 #1
5 1 2 52 -2 3 -3 -15 1 2 5 2 -2 3 -3 -15 1 2 5 2 -2 3 -3 -1
样例输出 #1
111
样例 #2
样例输入 #2
5 2 1 52 -2 3 -3 -15 2 1 5 2 -2 3 -3 -15 2 1 5 2 -2 3 -3 -1
样例输出 #2
111
样例 #3
样例输入 #3
5 1 1 10 1 2 3 45 1 1 1 0 1 2 3 45 1 1 1 0 1 2 3 4
样例输出 #3
000
提示
样例 \(1\) 解释
花费 \(p=1\) 的代价将 \(a_3\) 增加一,得到数列 \(b=[2,-2,3,-2,-1,2,-2,3,-2,-1,\cdots]\) 是美妙的,取 \(k_0=2\) 符合要求。
可以证明不存在代价更小的方案。
样例 \(2\) 解释
花费 \(q=1\) 的代价将 \(a_1\) 删除,得到数列 \(b=[2,3,-3,-1,2,3,-3,-1,\cdots]\) 是美妙的,取 \(k_0=0\) 符合要求。
可以证明不存在代价更小的方案。
数据范围
本题采用捆绑测试。只有通过子任务中所有测试点以及所有依赖的子任务,才能获得相应的分数。
对于全部数据:\(1\le n\le 10^5\),\(1\le p,q,r\le 10^9\),\(|a_i|\le 10^9\)。
- 子任务一(\(10\) 分):\(n=1\)。
- 子任务二(\(10\) 分):\(n\le 10\)。依赖子任务一。
- 子任务三(\(20\) 分):\(|a_i|\le 1\)。
- 子任务四(\(20\) 分):\(\sum|a_i|\le 10^5\)。依赖子任务三。
- 子任务五(\(40\) 分):无特殊限制。依赖子任务一、二、三、四。
分析
转化
转化一下:有一个长为 $ n $ 的数字环,从某一个下标沿某个方向循环遍历,遍历过程中累加环上的数字,当且仅当任意时刻数字之和 $ sum \ge 0$ 称其为美妙的。
因为 $ {b_i} $ 是无限长的,所以 $ S =\sum_{i=1}^n a_i $ 会不断累加,此时只有 $ S $ 的正负性对总和正负性有影响, $ S \lt 0 $ 必然导致总和从某一位置开始小于零。
条件证明
由上,很容易得到一个符合定义的 $ {a_i} $ 的必要不充分条件: $ S \ge 0 $ 。
以下给出充分性证明:
$ \large 证明:\ $
\[\exist x_0 \in N^* , 1 \le x_0 \le n , \forall j \in N^* ,1 \le j \le n \\ \sum_{k=x_0}^{x+j-1} a_{(k-1)\% n+1 } \ge 0 \]
即存在一个初始位置,使得前 $ n $ 步的 $ n $ 个和均大于等于零。
不妨从 $ i $ 开始,破环为链,以 $ i $ 为起点遍历 $ {a_i} $ ,对于 $ x_0 $ 有两种情况:
-
$ \exist x_0 \le k \le n,\sum_{j=x_0}^k a_j \lt 0 $ 此时找到第一个总和小于零的区间,划分出来,将总和归零从 $ k $ 下一位开始走。
-
$\forall x_0 \le k \le n,\sum_{j=x_0}^k a_j \ge 0 $ 这个后缀区间是美妙的。
可以发现每次得到情况一,左侧和的绝对值均小于等于右侧的绝对值( $ S \ge 0$ ),在经过若干次划分后必然存在一个后缀区间的和与左侧所有数之和大于零且该后缀区间是美妙的。从这个下标 $ h $ 开始循环遍历形成的 $ b_i $ 必然是美妙的。
所以操作三是无效的。只需考虑操作一和二,将原数组排序后比较删除和累加哪种更优,注意数列非空即可。
#include<bits/stdc++.h>using namespace std;const int N=1e5+100;long long n,p,q,r;long long g[N],sum,ans;int main(){scanf("%lld%lld%lld%lld",&n,&p,&q,&r);for(int i=1;i<=n;++i){scanf("%lld",g+i);sum+=g[i];}sort(g+1,g+1+n);if(sum>=0){cout<<0;return 0;}int tot=0;for(int i=1;i<=n;++i){if(g[i]>=0 || sum>=0){sum=0;break;}if(q>min(-g[i],-sum)*p){ans+=min(-g[i],-sum)*p;sum+=min(-sum,-g[i]);}else{if(tot==n-1)break;++tot;ans+=q;sum-=g[i];}}if(sum<0){if(tot<n-1)ans+=(-sum*p,q);elseans+=-sum*p;}cout<<ans;return 0;}#include<bits/stdc++.h> using namespace std; const int N=1e5+100; long long n,p,q,r; long long g[N],sum,ans; int main() { scanf("%lld%lld%lld%lld",&n,&p,&q,&r); for(int i=1;i<=n;++i){scanf("%lld",g+i);sum+=g[i];} sort(g+1,g+1+n); if(sum>=0){cout<<0;return 0;} int tot=0; for(int i=1;i<=n;++i) { if(g[i]>=0 || sum>=0){sum=0;break;} if(q>min(-g[i],-sum)*p) { ans+=min(-g[i],-sum)*p; sum+=min(-sum,-g[i]); } else { if(tot==n-1)break; ++tot; ans+=q; sum-=g[i]; } } if(sum<0) { if(tot<n-1) ans+=(-sum*p,q); else ans+=-sum*p; } cout<<ans; return 0; }#include<bits/stdc++.h> using namespace std; const int N=1e5+100; long long n,p,q,r; long long g[N],sum,ans; int main() { scanf("%lld%lld%lld%lld",&n,&p,&q,&r); for(int i=1;i<=n;++i){scanf("%lld",g+i);sum+=g[i];} sort(g+1,g+1+n); if(sum>=0){cout<<0;return 0;} int tot=0; for(int i=1;i<=n;++i) { if(g[i]>=0 || sum>=0){sum=0;break;} if(q>min(-g[i],-sum)*p) { ans+=min(-g[i],-sum)*p; sum+=min(-sum,-g[i]); } else { if(tot==n-1)break; ++tot; ans+=q; sum-=g[i]; } } if(sum<0) { if(tot<n-1) ans+=(-sum*p,q); else ans+=-sum*p; } cout<<ans; return 0; }
来源链接:https://www.cnblogs.com/Glowingfire/p/18587159
如有侵犯您的版权,请及时联系3500663466#qq.com(#换@),我们将第一时间删除本站数据。
暂无评论内容