n<=1000,3<=k<=10,ai<=100000
状压dp的题目,据出题人说是裸题,奈何我状压一直是最弱的= =,问了ymwdalao才知道怎么打。。讲道理基本上超过2000多B的状压我都不大会。。
设f[i][j][l]表示当前选到第i个,j是状态,表示i-k到i的状态,l表示有多少个三人桌。
那么明显,三人桌只能有3个,4个的话就可以被替代成为3个4人桌。
那么我们预处理val[i][j]表示i到i+k-1的状态为j的贡献,这个需要预处理一下。(lowbit(x)表示一个数最低的非0位)
再预处理一个trans[i,0/1,j]表示状态i放3/4人桌后可以转移到哪些状态。
那么就可以暴力枚举所有状态转移了。。
感觉好无脑的样子。。
看来还是我状压太弱了。。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=2e3+5;
typedef long long ll;
const ll inf=1e18;
int n,m,k;
int tot[N][2],trans[N][2][N],bin[20];
int a[N],bl[N],pre[N][N][5],tim;
ll f[N][N][5],val[N][N];
inline int lowbit(int x)
{
return x&(-x);
}
inline ll calc(int i,int s)
{
int cnt=0;
ll tot=0;
for(int tmp=s;tmp;tmp-=lowbit(tmp))
{
int x=lowbit(tmp);
x=lower_bound(bin,bin+k,x)-bin+1;
tot+=a[i+x-1];
cnt++;
}
if (cnt!=3&&cnt!=4)return 0;
tot=tot*12/cnt;
ll ans=0;
for(int tmp=s;tmp;tmp-=lowbit(tmp))
{
int x=lowbit(tmp);
x=lower_bound(bin,bin+k,x)-bin+1;
ans+=(a[i+x-1]*12-tot)*(a[i+x-1]*12-tot);
}
return ans;
}
inline void prework()
{
fo(i,0,bin[k]-1)
fo(j,0,bin[k]-1)
{
if((j|i)!=j)continue;
int tmp=j^i,s=0;
if (!(i&1)&&!(tmp&1))continue;
while (tmp)s++,tmp-=lowbit(tmp);
if (s==3)trans[i][0][++tot[i][0]]=j;
else if (s==4)trans[i][1][++tot[i][1]]=j;
}
fo(i,1,n-k+1)
fo(j,0,bin[k]-1)
val[i][j]=calc(i,j);
}
inline void dp()
{
fo(i,k,n)
fo(j,0,bin[k]-1)
fo(l,0,m)f[i][j][l]=inf;
f[k][0][0]=0;
fo(i,k,n)
fo(j,0,bin[k]-1)
fo(l,0,m)
if (f[i][j][l]<inf)
{
if (j&1)f[i+1][j>>1][l]=min(f[i+1][j>>1][l],f[i][j][l]);
if (l<m)
{
fo(x,1,tot[j][0])
if (f[i][j][l]+val[i-k+1][trans[j][0][x]^j]<f[i][trans[j][0][x]][l+1])
{
f[i][trans[j][0][x]][l+1]=f[i][j][l]+val[i-k+1][trans[j][0][x]^j];
pre[i][trans[j][0][x]][l+1]=j+1;
}
}
fo(x,1,tot[j][1])
if (f[i][j][l]+val[i-k+1][trans[j][1][x]^j]<f[i][trans[j][1][x]][l])
{
f[i][trans[j][1][x]][l]=f[i][j][l]+val[i-k+1][trans[j][1][x]^j];
pre[i][trans[j][1][x]][l]=j+1;
}
}
printf("%lld\n",f[n][bin[k]-1][m]);
}
inline void solve(int i,int j,int l)
{
if (i==k&&!j&&!l)return;
if (!pre[i][j][l])solve(i-1,j*2+1,l);
else
{
tim++;
pre[i][j][l]--;
int tmp=j^pre[i][j][l],cnt=0;
for(;tmp;tmp-=lowbit(tmp))
{
int x=lowbit(tmp);
x=lower_bound(bin,bin+k,x)-bin+1;
bl[i-k+1+x-1]=tim;
cnt++;
}
if (cnt==3)solve(i,pre[i][j][l],l-1);
else solve(i,pre[i][j][l],l);
}
}
int main()
{
freopen("friends.in","r",stdin);
freopen("friends.out","w",stdout);
scanf("%d%d",&n,&k);k++;
fo(i,1,n)scanf("%d",&a[i]);
if (n%4==1)m=3;
else if (n%4==2)m=2;
else if (n%4==3)m=1;
else m=0;
bin[0]=1;
fo(i,1,k)bin[i]=bin[i-1]*2;
prework();dp();
solve(n,bin[k]-1,m);
fo(i,1,n)printf("%d ",bl[i]);
return 0;
}