博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
“景驰科技杯”2018年华南理工大学程序设计竞赛 G. Youhane as "Bang Riot"(斜率DP)...
阅读量:4485 次
发布时间:2019-06-08

本文共 2483 字,大约阅读时间需要 8 分钟。

题目链接:

题意:中文题目,见链接

题解:设 sum[i] 为 a[i] 的前缀和,可得公式

dp[i] = min( dp[j] + ( sum[i] - sum[j] -  b[i] ) ^ 2 )

          = min( dp[j] + sum[j] ^ 2 + 2 * ( sum[i] - b[i] ) * ( sum[i] - sum[j] ) + sum[i] - b[i] ) ^ 2 

设 y = dp[j] + sum[j] ^ 2,k = sum[i] - b[i],x = sum[i] - sum[j],b = sum[i] - b[i] ) ^ 2

有 y = 2 * k * x + b

因为 k 的正负不确定,但 y 和 x 符合单调性,故可以二分找出第一个比当前点斜率大的点来维护下凸性(注意最好手写二分,使用lower_bound可能会出错)

 

1 #include 
2 using namespace std; 3 #define ll long long 4 #define ull unsigned long long 5 #define mst(a,b) memset((a),(b),sizeof(a)) 6 #define mp(a,b) make_pair(a,b) 7 #define pi acos(-1) 8 #define pii pair
9 #define pb push_back10 const int INF = 0x3f3f3f3f;11 const double eps = 1e-6;12 const int MAXN = 1e6 + 10;13 const int MAXM = 1e3 + 10;14 const ll mod = 100000073;15 16 int n,tail;17 int q[MAXN];18 ll a[MAXN],b[MAXN],sum[MAXN],dp[MAXN];19 double k[MAXN];20 21 ll sqr(ll x) {22 return x * x;23 }24 25 ll getup(int j,int k) {26 return dp[j] + sqr(sum[j]) - (dp[k] + sqr(sum[k]));27 }28 29 ll getdown(int j,int k) {30 return 2ll * (sum[j] - sum[k]);31 }32 33 int findd(double x) {34 int l = 0, r = tail - 1, ans = 0;35 while(l <= r) {36 int mid = (l + r) >> 1;37 ll up = dp[q[mid]] + sqr(sum[q[mid]]) - (dp[q[mid - 1]] + sqr(sum[q[mid - 1]]));38 ll down = 2.0 * (sum[q[mid]] - sum[q[mid - 1]]);39 if(up <= down * x) l = mid + 1, ans = mid;40 else r = mid - 1;41 }42 return q[ans];43 }44 45 int main() {46 #ifdef local47 freopen("data.txt", "r", stdin);48 #endif49 sum[0] = dp[0] = 0;50 while(~scanf("%d",&n)) {51 for(int i = 1; i <= n; i++) {52 scanf("%lld",&a[i]);53 sum[i] = sum[i - 1] + a[i];54 }55 for(int i = 1; i <= n; i++) scanf("%lld",&b[i]);56 tail = 0;57 q[tail++] = 0;58 for(int i = 1; i <= n; i++) {59 int id = findd(1.0 * (sum[i] - b[i]));60 dp[i] = dp[id] + sqr(sum[i] - sum[id] - b[i]);61 while(1 < tail && getup(q[tail - 1],q[tail - 2]) * getdown(i,q[tail - 1]) >= getup(i,q[tail - 1]) * getdown(q[tail - 1],q[tail - 2]))62 tail--;63 if(getdown(i,q[tail - 1]) == 0) k[tail] = 1e18;64 else k[tail] = 1.0 * getup(i,q[tail - 1]) / getdown(i,q[tail - 1]);65 q[tail++] = i;66 }67 printf("%lld\n",dp[n]);68 }69 return 0;70 }

 

转载于:https://www.cnblogs.com/scaulok/p/9770065.html

你可能感兴趣的文章
Java 重写(Override)与重载(Overload) (转子Runood)
查看>>
Linux常用命令总结
查看>>
飞扬的小鸟(NOIP2014)(丧病DP题)
查看>>
UITableView 的使用小点
查看>>
SpringBoot项目在新电脑上的配置运行,包括JDK+MAVEN+Git+SpringBoot配置等
查看>>
bzoj 3754: Tree之最小方差树 模拟退火+随机三分
查看>>
基于JavaMail的Java邮件发送:简单邮件发送
查看>>
那些年,我追过的绘图工具
查看>>
单例实现方式
查看>>
04 Python并发编程(守护进程,进程锁,进程队列)
查看>>
win7下安装fedora16
查看>>
ffmpeg视频压缩与分割
查看>>
解决&quot;VC6.0的ClassView里不能显示类或成员变量&quot;问题
查看>>
解决Ueditor在bootstarp 模态框中全屏问题
查看>>
POJ 1006 Biorhythms
查看>>
dubbo+zookeeper注册服务报错问题:No service registed on zookeeper
查看>>
极验滑动验证登录
查看>>
求多个数的质因子
查看>>
laravel的orm作用
查看>>
文件锁
查看>>