首页 > 其他分享 >「SDOI2016」征途 TJ

「SDOI2016」征途 TJ

时间:2023-02-03 00:22:18浏览次数:55  
标签:frac sum times TJ 征途 SDOI2016 inline void dp

「SDOI2016」征途 TJ

题目传送门

题目大意:

有 \(n\) 个块,给出其块长,将其分为 \(m\) 组,使得 每组内长度之和 的方差最小。

输出 \(v \times m^2\),其中 \(v\) 是方差。

思路:

方差是什么?我没学过。

首先给一下方差的定义,防止忘了的同学。

统计中的方差(样本方差)是每个样本值与全体样本值的平均数之差的平方值的平均数

说白了,记 \(x\) 为数列 \(a\) 的平均数,构造数列 \(b\) 使得 \(b_i=(a_i-x)^2\),方差就是 \(b\) 数列中的平均数。

看到这种没见过的数论问题,我们首先考虑当个老老实实的 ctjer。

记 \(v\) 为方差,\(r_i\) 为第 \(i\) 组的长度,\(\overline r\) 为 \(r\) 数组的平均数。

则有:

\[\begin{aligned} v &= \frac{\sum_{i=1}^m (r_i-{\overline r})^2}{m} \\ &= \frac{\sum_{i=1}^m (r_i^2+ {\overline r}^2 - 2 \times r_i \times {\overline r})}{m}\\ &= \frac{m \times {\overline r}^2 + \sum_{i=1}^m r_i^2 - 2 \times {\overline r} \times \sum_{i=1}^m r_i}{m} \\ &= \frac{m \times (\frac{\sum_{i=1}^m r_i}{m})^2 + \sum_{i=1}^m r_i^2 - 2 \times (\frac{\sum_{i=1}^m r_i}{m}) \times \sum_{i=1}^m r_i}{m} \\ &= \frac{\frac{(\sum_{i=1}^m r_i)^2}{m} + \sum_{i=1}^m r_i^2 - 2 \times \frac{(\sum_{i=1}^m r_i)^2}{m}}{m} \\ &= \frac{\sum_{i=1}^m r_i^2}{m} - \frac{(\sum_{i=1}^m r_i)^2}{m} \end{aligned} \]

(这柿子真不是人打的)

要求答案为:

\(v \times m^2 = m^2 \times (\frac{\sum_{i=1}^m r_i^2}{m} - \frac{(\sum_{i=1}^m r_i)^2}{m^2})=m \times \sum_{i=1}^m r_i^2 + (\sum_{i=1}^m r_i)^2\)

瞪眼法,可以发现后者就是我们所有块的总长度,则只需解决 \(\sum_{i=1}^mr_i^2\),下文记为 \(now\)。

设 \(dp_{i,j}\) 表示考虑前 \(i\) 块,第 \(i\) 块是第 \(j\) 组最后一个时,\(now\) 的最小值。

暴力转移:\(dp_{i,j}=\min_{k=0}^{i-1}(dp_{k,j-1}+(sum_k-sum_i)^2)\),其中 \(sum_i\) 为块长的前缀和。

这个复杂度是 \(n^2\) 的,只能有 \(70pts\),可以滚动数组 0/1 滚一下,得到 \(90pts\),当然,还可以用类似于 01 背包的方法,倒序循环 \(k\),直接压到一维,不过仍然是 \(90pts\)。

这里给出后两种代码:

//滚动数组
read(n,m);
for(int i=1;i<=n;++i) read(sum[i]),sum[i]+=sum[i-1];
memset(dp,0x3f,sizeof dp);
dp[0][0]=0;
for(int j=1;j<=m;++j){
    for(int i=1;i<=n;++i){
        for(int k=0;k<i;++k){
            dp[j&1][i]=min(dp[j&1][i],dp[(j&1)^1][k]+(sum[k]-sum[i])*(sum[k]-sum[i]));
        }
    }
}
ans=m*dp[m&1][n]-sum[n]*sum[n];
write(ans);

//直接压成一维
read(n,m);
for(int i=1;i<=n;++i) read(sum[i]),sum[i]+=sum[i-1];
memset(dp,0x3f,sizeof dp);
dp[0]=0;
for(int j=1;j<=m;++j){
    for(int i=n;i>=1;--i){
        for(int k=0;k<i;++k){
            dp[i]=min(dp[i],dp[k]+(sum[k]-sum[i])*(sum[k]-sum[i]));
        }
        // for(int k=0;k<i;++k){
        //     dp[j&1][i]=min(dp[j&1][i],dp[(j&1)^1][k]+(sum[k]-sum[i])*(sum[k]-sum[i]));
        // }
    }
}
write(m*dp[n]-sum[n]*sum[n]);

优化:

我们发现这个暴力已经压榨到极限了,\(90pts\) 是最高了。

考试的时候当然可以大胆走人,不过平时还是要正解 A 掉。

我们去掉最值符号,对方程变式:

\[\begin{aligned} dp_{k,j-1} &= dp_{i,j}-(sum_k-sum_i)^2 \\ &= dp_{i,j}-sum_k^2-sum_i^2+2 \times sum_k \times sum_i \\ \end{aligned} \]

此时发现方程左右都包含 \(k\),但右侧有俩,我们移一个 \(sum_k^2\)。

\[dp_{k,j-1} + sum_k^2 = 2 \times sum_i \times sum_k + dp_{i,j}-sum_i^2 \]

现在使用瞪眼法,不难发现,\(2 \times sum_i\) 是斜率,\(dp_{i,j}-sum_i^2\) 是截距。

由于 \(sum_k\) 单调递增,所以 \(sum_k^2\) 也是单调递增的,因此求得截距最小时 \(dp_{k,j-1}\) 也取得最小值,用单调队列维护一个对应的下凸壳,套任务安排2的模板即可。

要是您实在懒得,我就这么写上来吧:

  • 原本是:\(dp_{k1,j-1}+sum_{k1}^2+sum_i^2-2\times sum_{k1} \times sum_i < dp_{k2,j-1} + sum_{k2}^2 + sum_i^2 - 2 \times sum_{k2}\times sum_i\)
  • 变式得到:\((dp_{k1,j-1}+sum_{k1}^2)-(dp_{k2,j-1}+sum_{k2}^2) < 2 \times sum_i \times (sum_{k1}-sum_{k2})\)

这个就可以拿去队尾踢人了,队首同理。

最后答案就是 \(m \times dp_{n,m} +now\)。

细节:

  1. 要开 long long。
  2. 不要压成一维,转移和决策范围的方向是反着的,只能两个数组之间滚动。
  3. dp[0][0]=dp[1][0]=0lws踩过此坑。
  4. 单调队列最初插入个 0,相信大家都踩过,在不同的题
  5. 建议把一些长得不能说是很像,只能说是除了参数一模一样的部分封装一下,丢进函数看起来就没那么伤眼睛。lyh:你是懂封装的。

Code:

(可以拿走,我是指缺省源)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<initializer_list>
using ll=long long;
static char buf[1000000],*p1=buf,*p2=buf,obuf[1000000],*p3=obuf;
#define flush() fwrite(obuf,p3-obuf,1,stdout)
#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++
#define putchar(x) (p3-obuf<1000000)?(*p3++=x):(flush(),p3=obuf,*p3++=x)
#define out_end (flush(),0)
template<typename T> inline void read(T&);
template<typename T> inline void write(T);
inline void read(char*);
inline void write(char);
inline void write(const char*);
template<typename... Args> inline void read(Args&...);
template<typename... Args> inline void write(Args...);
template<typename Type> const Type& max(const Type& x,const Type& y){return x<y?y:x;}
template<typename Type> const Type& min(const Type& x,const Type& y){return x<y?x:y;}
const int N=3005;
int n,m,sum[N],que[N],head,tail;
ll dp[2][N];
inline ll calc(int i,int k){return dp[(i&1)^1][k]+sum[k]*sum[k];}
inline int get(int k){return sum[k]<<1;}
signed main(){
    read(n,m);
    for(int i=1;i<=n;++i) read(sum[i]),sum[i]+=sum[i-1];
    memset(dp,0x3f,sizeof dp);
    dp[0][0]=dp[1][0]=0;
    for(int j=1;j<=m;++j){
        que[head=tail=1]=0;
        for(int i=1;i<=n;++i){
            while(head<tail&&(calc(j,que[head+1])-calc(j,que[head]))<=sum[i]*(get(que[head+1])-get(que[head]))) ++head;
            dp[j&1][i]=calc(j,que[head])-get(que[head])*sum[i]+sum[i]*sum[i];
            while(head<tail&&(calc(j,que[tail])-calc(j,que[tail-1]))*(get(i)-get(que[tail]))>=(calc(j,i)-calc(j,que[tail]))*(get(que[tail])-get(que[tail-1]))) --tail;
            que[++tail]=i;
        }
    }
    write(m*dp[m&1][n]-sum[n]*sum[n]);
    return out_end;
}
template<typename T> inline void read(T& x){
	x=0;bool flag=0;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') flag=1;
	if(flag) for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)-(ch&15);
	else for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch&15);
}
template<typename T> inline void write(T x){
    static char sta[40];
    int top=0;
    if(x<0){
        putchar('-');
        do sta[top++]=((-x)%10)^48,x/=10;
        while(x);
    }
    else{
        do sta[top++]=(x%10)^48,x/=10;
        while(x);
    }
    while(top) putchar(sta[--top]);
}
inline void read(char* str){while((*str=getchar())==' '||*str=='\n');while((*++str=getchar())!=' '&&*str!='\n');*str=0;}
inline void write(char x){putchar(x);}
inline void write(const char* str){while(*str!='\0') putchar(*str++);}
template<typename... Args> inline void read(Args& ...args){(void)std::initializer_list<int>{(read(args),0)...};}
template<typename... Args> inline void write(Args ...args){(void)std::initializer_list<int>{(write(args),0)...};}

标签:frac,sum,times,TJ,征途,SDOI2016,inline,void,dp
From: https://www.cnblogs.com/LQ636721/p/17087825.html

相关文章

  • [题解] P2685 [TJOI2012]桥 思路整理
    题目大意给一张\(n\)个点\(m\)条边的图,求删去一条边后最短路长度的最大值与对应删边方案数。思路首先考虑,如果删去的这条边不在原图最短路上,那么新图最短路长度与原......
  • FastJason 1.2.22-1.2.24 TemplatesImpl利用链分析
    前言休息了好像有一周了(慢慢的罪恶感),昨天在打比赛的时候做了一个php-cms的审计,然后激起了学习的热情。之前打比赛的时候遇到过fastjson的题,当时也就是直接用poc利用了,也......
  • 「POJ3076」Sudoku TJ
    「POJ3076」SudokuTJ为什么要用DLX呢?DFS他不香吗!题意:略去不讲(数独还没玩过?滚回去玩吧!)思路:DFS,判断方案是否可行。\(9\times9\)的数独问题中,我们采用的策略是:优......
  • NextJS(青训营)
    nodejs应用场景前端工程化(webpackviteesbuildbeble……)web服务端应用(vercel)Electron跨桌面端应用(vscode)优点:学习曲线平滑开发效率较高运行效率相对较高社区......
  • spring boot——json解析示例——fastjson——使用fastJson将json与对象、集合、数组
                 ......
  • spring boot——json解析示例——fastjson
    多层嵌套JSON类型数据解析简单来说:“key”:“value”-->此时value为String “key":0-->此时value为int “key”:{“k1”:“v1”}-->此时value为JSONObject......
  • Java(FastJson) 解析 JSON文件
    依赖<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.73</version></dependency>JSON文件内容publicclassMy......
  • ExtJS-组件查询
    更新记录点击查看>2023年1月6日更新Ext.getCmp>2022年12月3日开始。ExtJS教程汇总:https://www.cnblogs.com/cqpanda/p/16328016.htmlFindingcomponentsbase......
  • springboot 怎么启动aop @EnableAspectJAutoProxy
    SpringBoot项目使用aophttps://blog.csdn.net/qq_39176307/article/details/124714191Spring-AOPSpringBoot自动配置和启动SpringAOPhttps://www.bbsmax.com/A/QV5ZX3......
  • ExtJS-自定义事件(观察者模式)实现
    更新记录2023年1月6日从笔记迁移到博客。转载请注明出处:ExtJS教程汇总:https://www.cnblogs.com/cqpanda/p/16328016.html使用Ext.util.Observable类型即可。代码......