首先考虑分离操作1,2,先全做操作1再加上操作2,所以我们可以转化为这样的一个问题:
选择数列中的一部分,其中最前面选的记为S,最后面记为E,满足S−E>=K−1且选择的相邻两数之间间距不大于1
思考一下容易发现最优情况下S−E=K−1或K,枚举一下最开始选取的点l,分讨是K−1还是K就行了
fl−1,0=0,fl−1,1=al−1fi,0=fi−1,1,fi,1=min(fi−1,0,fi−1,1)+ai
但是这样是O(n2)的,不能通过
然后我们就可以使用神秘的矩阵乘法优化这个式子,具体如下
定义新运算矩阵A=n×m,B=m×r
(A⨁B)i,j=mink=1m(Ai,k+Bk,j)
则转移方程为
[fi,0fi,1]=[∞0aiai]⨁[fi−1,0fi−1,1]
放个线段树进行区间操作然后区间查询答案即可
AC代码
Details
#include<bits/stdc++.h>
using namespace std;
#define QAQ return
#define QWQ return 0;
#define ll long long
#define pii pair< int,int >
const int N=2e5+10;
const ll inf=1e18;
struct matrix
{
int n, m;
ll mat[3][3];
inline matrix( int _n,int _m )
{
memset( mat,0,sizeof mat );
n=_n, m=_m;
}
inline void read()
{
for( int i=1;i<=n;i++ ) for( int j=1;j<=m;j++ ) cin>>mat[i][j];
}
inline void print()
{
for( int i=1;i<=n;i++ ) for( int j=1;j<=m;j++ ) cout<<mat[i][j]<<" \n"[j==m];
}
inline void E()
{
for( int i=1;i<=n;i++ ) mat[i][i]=1;
}
inline matrix operator +( const matrix &a )const
{
matrix ans( n,a.m );
ans.mat[1][1]=ans.mat[1][2]=ans.mat[2][1]=ans.mat[2][2]=inf;
for( int k=1;k<=m;k++ ) for( int i=1;i<=n;i++ ) for( int j=1;j<=a.m;j++ ) ans.mat[i][j]=min( ans.mat[i][j],mat[i][k]+a.mat[k][j] );
return ans;
}
inline matrix operator *( const matrix &a )const
{
matrix ans( n,a.m );
for( int k=1;k<=m;k++ ) for( int i=1;i<=n;i++ ) for( int j=1;j<=a.m;j++ ) ans.mat[i][j]+=mat[i][k]*a.mat[k][j];
return ans;
}
};
inline matrix quick_power( matrix a,int k )
{
matrix ans( a.n,a.n );
ans.E();
while( k )
{
if( k&1 ) ans=ans*a;
a=a*a, k>>=1;
}
return ans;
}
ll a[N];
struct segment_tree
{
int l, r;
matrix mt;
inline segment_tree() : mt( 2,2 ){}
}st[N<<2];
inline void pushup( int p ){ st[p].mt=st[p<<1|1].mt+st[p<<1].mt; }
inline void build( int p,int l,int r )
{
st[p].l=l, st[p].r=r;
if( l == r )
{
st[p].mt.mat[1][1]=inf;
st[p].mt.mat[1][2]=0;
st[p].mt.mat[2][1]=a[l];
st[p].mt.mat[2][2]=a[l];
QAQ;
}
int mid=l+r>>1;
build( p<<1,l,mid );
build( p<<1|1,mid+1,r );
pushup( p );
}
inline matrix query( int p,int l,int r )
{
if( l <= st[p].l && st[p].r <= r ) QAQ st[p].mt;
int mid=st[p].l+st[p].r>>1;
matrix ans( 2,2 );
if( mid >= l ) ans=query( p<<1,l,r );
if( mid < r ) ans=( mid >= l ? query( p<<1|1,l,r )+ans : query( p<<1|1,l,r ) );
QAQ ans;
}
inline void sovel()
{
int n, k;
cin>>n>>k;
a[0]=inf;
for( int i=1;i<=n;i++ ) cin>>a[i];
build( 1,1,n );
ll ans=inf;
for( int l=1, r=k;r<=n;l++, r++ )
{
matrix mt=query( 1,l,r );
ans=min( ans,mt.mat[2][1] );
if( l > 1 ) ans=min( ans,min( mt.mat[1][2],mt.mat[2][2] )+a[l-1] );
}
cout<<ans<<"\n";
}
int main()
{
ios::sync_with_stdio( false );
cin.tie( nullptr ), cout.tie( nullptr );
int t;
for( cin>>t;t;t-- ) sovel();
QWQ
}
时间复杂度:O(nlogn)