题解:AT_arc219_f [ARC219F] Range Division
约定
考虑如下问题:
给定
关键结论:答案为
证明:考虑构造最长公共子序列,设
每次删去一个字符,显然需要先删除
因此考虑建图,连边
这对应把图上所有可达的点都标记,这显然不会标记到
(这里其它题解的证明都非常简洁,可能其实很 trivial?)。
考虑若规定不能选包含
#include<bits/stdc++.h>
#define up(i,l,r) for(int i=(l);i<=(r);++i)
#define down(i,l,r) for(int i=(l);i>=(r);--i)
#define pi pair<int,int>
#define p1 first
#define p2 second
#define m_p make_pair
#define pb push_back
#define eb emplace_back
using namespace std;
typedef long long ll;
inline ll read(){
ll x=0;short t=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*t;
}
const int m=60;
int n,len[35];ll a[35];
int lcs[2105][2105],dp[35][2005];
void slv(){
n=read();up(i,1,n)a[i]=read(),len[i]=a[i]?__lg(a[i])+1:0;
up(i,0,n*m)dp[1][i]=len[1]+i;
up(i,2,n){
memset(dp[i],0x3f,sizeof(dp[i]));
auto g=[&](int p,int x){if(p<=len[x])return (a[x]>>p-1)&1;return 0ll;};
memset(lcs,0,sizeof(lcs));
up(j,1,n*m+len[i-1])
up(k,1,n*m+len[i])
lcs[j][k]=max(max(lcs[j][k-1],lcs[j-1][k]),lcs[j-1][k-1]+(g(j,i-1)==g(k,i)));
up(j,0,n*m)up(k,0,n*m)
dp[i][k]=min(dp[i][k],dp[i-1][j]+len[i]+k-lcs[j+len[i-1]][k+len[i]]);
}
int res=1e9;
up(i,0,n*m)res=min(res,dp[n][i]);
printf("%d\n",res);
}
int main(){
// freopen("1.in","r",stdin),freopen("1.out","w",stdout);
int t=read();while(t--)slv();
return 0;
}