题意简述
以下只考虑红色值。有nnn个色块,每个色块占cnticnt_icnti个像素,红色值强度为valival_ivali。选择kkk个整数v1,v2⋯vkv_1,v_2\cdots v_kv1,v2⋯vk,定义"平方误差"为
∑i=1ncnti×minj=1k{(vali−vj)2}\sum\limits_{i=1}^{n}cnt_i\times min_{j=1}^{k}\{(val_i-v_j)^2\}i=1∑ncnti×minj=1k{(vali−vj)2},(意会理解:对于第iii个色块,选择一个vjv_jvj满足(vali−vj)2(val_i-v_j)^2(vali−vj)2最小,然后用这个最小值乘上cnticnt_icnti,把每个色块得到的这些和加起来)。
合理安排使得"平方误差"最小。
数据
输入
第一行两个正整数n,kn,kn,k
接下来nnn行,每行两个数valival_ivali和cnticnt_icnti。保证valival_ivali 升序
输出
输出最小的"平方误差"。
样例
输入
2 1
50 20000
150 10000
输出
66670000
输入
2 2
50 20000
150 10000
输出
0
输入
4 2
0 30000
25 30000
50 30000
255 30000
输出
37500000
思路
显然是DPDPDP吧。。。像这种题,题做多了,一样就能看出来应该设dp[i][j]dp[i][j]dp[i][j]为考虑前iii个色块,选择了jjj个整数。显然,答案就是dp[n][k]dp[n][k]dp[n][k]。那么,如何转移呢?
对于dp[i][j]dp[i][j]dp[i][j]我们选择一个断点kkkkkk(为了不和kkk重名),那么此时就要用dp[kk][j−1]dp[kk][j-1]dp[kk][j−1]+(kk+1kk+1kk+1到iii选择某整数的最优解)的值来更新dp[i][j]dp[i][j]dp[i][j]。现在我们发现关键了,(kk+1kk+1kk+1到iii选择某整数的最优解)这个值怎么求?
如果我们要暴力求的话,那么我们的dpdpdp就是四次方的dpdpdp,就会FFT(fast−fast−TLE)FFT(fast-fast-TLE)FFT(fast−fast−TLE)了。所以我们考虑 打表 预处理。首先枚举转移到了哪个点kkkkkk(也是为了不和kkk重名),然后枚举所有区间,一边枚举一遍加上和,然后更新最小值。预处理就是O(n3)O(n^3)O(n3)的了。这样,我们的dpdpdp也就是O(n3)O(n^3)O(n3)的了,能过。
代码:
#include<bits/stdc++.h>
using namespace std;
namespace Flandle_Scarlet
{
#define N 300
#define int long long
int n,k;
struct col
{
int val,cnt;
}a[N];
void Input()
{
scanf("%lld%lld",&n,&k);
if (k>=n)
{
puts("0\n");
exit(0);
}
//k>=n的情况,直接选择一些整数和n个色块重合,答案就是0了。这个特判掉
for(int i=1;i<=n;++i)
{
int val,cnt;scanf("%lld%lld",&val,&cnt);
a[i]=(col){val,cnt};
}
}
int dp[N][N];
int dis[N][N];
//dis[l][r]表示l到r整体都选择某个点的最小代价
int sqr(int x){return x*x;}
void DP()
{
memset(dis,0x3f,sizeof(dis));
for(int kk=0;kk<=256;++kk)
//枚举断点kk
{
for(int i=1;i<=n;++i)
{
int ans=0;
for(int j=i;j<=n;++j)
{
ans+=sqr(a[j].val-kk)*a[j].cnt;
//叠加的
dis[i][j]=min(dis[i][j],ans);
//更新最小值
}
}
}
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;//注意边界!!!
for(int i=1;i<=n;++i)
{
for(int j=1;j<=k and j<=i;++j)
{
for(int kk=0;kk<i;++kk)
{
dp[i][j]=min(dp[i][j],dp[kk][j-1]+dis[kk+1][i]);
//这个转移就很显然了。。。
}
}
}
printf("%lld\n",dp[n][k]);
}
void Main()
{
Input();
DP();
}
};
main()
{
Flandle_Scarlet::Main();
return 0;
}