FZU - 2302 (DP optimización pendiente)

Cuestión tiene por objeto: un segmento de anillo se divide en k, encontrar cómo hacer que la sub-sub-segmento de la suma de mínimos cuadrados.

Pensando: proporcionado DP [i] [k] indica la-ésimo i ex valor mínimo se divide en segmentos k, fácilmente dp disponible [i] [k] = min (dp [i] [j], dp [i] [k-1 ] + ([i] suma -sum [j-1]) * ([i suma] -sum [j-1])). algoritmo puede ser escrito en un n ^ 4, pero n es 200, es la suma observó aumentando.

Proporcionada k1 <k2.

Orden F. [K2] [k1] representa una relación k1 a k2 es decir excelente. Así F [k2] [k1] se puede escribir como una forma de expresión

dp [i] [k1] + (suma [i] -sum [k1]) * (suma [i] -sum [k1]) <= dp [i] [k1] + (suma [i] -sum [k2]) * (suma [i] -sum [k2]) (式子 一).

Simplificación obtiene suma [k1] * suma [k1] -sum [k2] * suma [k2] + dp [k1] [k1] -dp [k2] [k1] <= 2 * (suma [k1 ] -sum [k2]) * suma [i] (ecuación II).

Debido a que la suma se incrementa entonces por la tarde i + 1, i + 2 ....., k1, k2 caso donde una expresión constante siempre se satisface, entonces la relación preferida debería ser siempre k2 k1. Luego, más tarde ya no podremos ser considerado como un k1.

Encontramos que si F [j] [i] <= F [k] [j], es decir, K superior a j, entonces j puede ser eliminada.

#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;

#define INF 0x3f3f3f3f
typedef long long ll;
long long sum[300],dp[205][205];
long long a[300],b[300];

ll getx(ll k1, ll k2,ll k)
{
	return sum[k1]*sum[k1]-sum[k2]*sum[k2]+dp[k1][k-1]-dp[k2][k-1];
}
ll gety(ll k1,ll k2)
{
	return 2*(sum[k1]-sum[k2]);
}
ll q[1005];
int main()
{
	int t;cin>>t;
	while(t--)
	{
		int n,K;cin>>n>>K;
		for(int i=1;i<=n;i++) cin>>b[i];
		long long ans=INF;
		for(int l=1;l<=n;l++)
		{
			for(int j=1;j<=n;j++) a[j]=b[((j+l-1)>n?(j+l-1-n):(j+l-1))];
			for(int j=1;j<=n;j++) sum[j]=sum[j-1]+a[j],dp[j][1]=sum[j]*sum[j];
			for(int k=2;k<=K;k++)
			{
				int head=0,tail=0;
				q[tail++]=k-1;
				for(int i=k;i<=n;i++)	//前i个分为k段
				{
					while(head<tail-1&&getx(q[head+1],q[head],k)<=sum[i]*gety(q[head+1],q[head])) head++;
					//cout<<head<<endl;
					dp[i][k]=dp[q[head]][k-1]+(sum[i]-sum[q[head]])*(sum[i]-sum[q[head]]);
					//printf("%d %d %lld\n",i,k,dp[i][k]);
					while(head<tail-1&&getx(q[tail-1],q[tail-2],k)*gety(i,q[tail-1])>=getx(i,q[tail-1],k)*gety(q[tail-1],q[tail-2])) tail--; 
					q[tail++]=i;
				/*	for(int j=0;j<i;j++)		//优化掉这层 
					{
						
						dp[i][k]=min(dp[i][k],dp[j][k-1]+(sum[i]-sum[j])*(sum[i]-sum[j]));		//i~k为一段
						//printf("%d %d %lld\n",i,k,dp[i][k]);
						
					}*/
				}
			}
			ans=min(ans,dp[n][K]);
		}
		cout<<ans<<endl;
	}
	return 0;
}

 

Publicados 155 artículos originales · ganado elogios 32 · Vistas a 30000 +

Supongo que te gusta

Origin blog.csdn.net/qq_37632935/article/details/89458126
Recomendado
Clasificación