JZOJ 5925. 【NOIP2018模拟10.25】naive 的瓶子

xiaoxiao2025-11-15  6

Description

众所周知,小 naive 有 n 个瓶子,它们在桌子上排成一排。第 i 个瓶子的颜色为 ci,每个瓶子都有灵性,每次操作可以选择两个相邻的瓶子,消耗他们颜色的数值乘积的代价将其中一个瓶子的颜色变成另一个瓶子的颜色。 现在 naive 要让所以瓶子的颜色都一样,操作次数不限,但要使得操作的总代价最小。

Input

输入文件为 colour.in。 一个测试点内多组数据。 第一行,一个正整数 T,表示数据组数。 每组数据内: 第一行一个整数 n,为瓶子的个数。 第二行共 n 个整数,第 i 个整数为第 i 个瓶子的颜色 ci。

Output

输入文件为 colour.out。 共一行,一个整数,为最小的总代价。

Sample Input

4 7 4 6 10

Sample Output

92

样例解释

{7 4 6 10}− > {4 4 6 10}− > {4 4 4 10}− > {4 4 4 4}。 总代价为 7 × 4 + 4 × 6 + 4 × 10 = 92。

Data Constraint

1 ≤ T ≤ 10。 对于测试点内的每组数据:

Solution

懒得多想的我这题的做法十分差劲,时空复杂度均为 O ( n 3 ) O(n^3) O(n3)

f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k] 表示区间 [ i , j ] [i,j] [i,j] 被染成颜色 k k k(离散化)所需的最小代价。

转移的话没有必要一段一段的转移,我们只需将一个状态往外扩展一位即可。

枚举时区间长度要从小到大枚举,这样状态转移就会不重不漏。

关于转移的话,将可能会染的两种颜色都分别转移即可。

Code

#include<cstdio> #include<cstring> #include<cctype> using namespace std; typedef long long LL; const int N=305,M=1e5+5; const LL inf=3e18; int c[N],bz[M],v[N]; LL f[N][N][N]; inline int read() { int X=0,w=0; char ch=0; while(!isdigit(ch)) w|=ch=='-',ch=getchar(); while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } inline LL min(LL x,LL y) { return x<y?x:y; } int main() { freopen("colour.in","r",stdin); freopen("colour.out","w",stdout); int T=read(); while(T--) { int n=read(),num=0; memset(bz,0,sizeof(bz)); memset(f,60,sizeof(f)); for(int i=1;i<=n;i++) { c[i]=read(); if(!bz[c[i]]) { bz[c[i]]=++num; v[num]=c[i]; } f[i][i][bz[c[i]]]=0; } for(int l=0;l<n;l++) for(int i=1,j=i+l;j<=n;i++,j++) for(int k=1;k<=num;k++) if(f[i][j][k]<inf) { if(i>1) { if(c[i-1]==v[k]) f[i-1][j][k]=min(f[i-1][j][k],f[i][j][k]); else { f[i-1][j][k]=min(f[i-1][j][k],f[i][j][k]+(LL)c[i-1]*v[k]); f[i-1][j][bz[c[i-1]]]=min(f[i-1][j][bz[c[i-1]]],f[i][j][k]+(LL)c[i-1]*(j-i+1)*v[k]); } } if(j<n) { if(c[j+1]==v[k]) f[i][j+1][k]=min(f[i][j+1][k],f[i][j][k]); else { f[i][j+1][k]=min(f[i][j+1][k],f[i][j][k]+(LL)c[j+1]*v[k]); f[i][j+1][bz[c[j+1]]]=min(f[i][j+1][bz[c[j+1]]],f[i][j][k]+(LL)c[j+1]*(j-i+1)*v[k]); } } } LL ans=inf; for(int i=1;i<=num;i++) ans=min(ans,f[1][n][i]); printf("%lld\n",ans); } return 0; }
转载请注明原文地址: https://www.6miu.com/read-5039680.html

最新回复(0)