网站建设美化中期报告百度网盘网页版登录
ARC126D Pure Straight
题目大意
给一个长度为nnn的整数序列A=(a1,a2,…,an)A=(a_1,a_2,\dots,a_n)A=(a1,a2,…,an),其中ai∈[1,k]a_i\in [1,k]ai∈[1,k]。
你可以做如下操作任意次:
- 交换相邻两个元素
求最小的操作次数,使得序列AAA满足下列条件:
- AAA包含(1,2,…,k)(1,2,\dots,k)(1,2,…,k)这个子串
2≤k≤16,k≤n≤2002\leq k\leq 16,k\leq n\leq 2002≤k≤16,k≤n≤200
题解
我们可以先将在111到kkk内的数移到一段,然后在这一段区间内排序。
令构成子串的元素的下标从小到大依次为c1,c2,…,cnc_1,c_2,\dots,c_nc1,c2,…,cn,中点位置为mid=⌊k2⌋mid=\lfloor\dfrac k2\rfloormid=⌊2k⌋,则显然让所有acia_{c_i}aci向acmida_{c_mid}acmid移动是最优的,总步数为
(∑i=1mid−1(cmid−mid+i)−ci)+(∑i=mid+1kci−(cmid+i−mid))(\sum\limits_{i=1}^{mid-1}(c_{mid}-mid+i)-c_i)+(\sum\limits_{i=mid+1}^kc_i-(c_{mid}+i-mid))(i=1∑mid−1(cmid−mid+i)−ci)+(i=mid+1∑kci−(cmid+i−mid))
我们发现这个式子中的许多地方可以抵消,最后式子可变为
(∑i=mid+1kci)−(∑i=1mid−1ci)−cmid×(n%2==0)+mid×(n%2==0)+(∑i=1mid−1i)−(∑i=mid+1ki)(\sum\limits_{i=mid+1}^kc_i)-(\sum\limits_{i=1}^{mid-1}c_i)-c_{mid}\times (n\%2==0)+mid\times(n\%2==0)+(\sum\limits_{i=1}^{mid-1}i)-(\sum\limits_{i=mid+1}^ki)(i=mid+1∑kci)−(i=1∑mid−1ci)−cmid×(n%2==0)+mid×(n%2==0)+(i=1∑mid−1i)−(i=mid+1∑ki)
后面mid×(n%2==0)+(∑i=1mid−1i)−(∑i=mid+1ki)mid\times(n\%2==0)+(\sum\limits_{i=1}^{mid-1}i)-(\sum\limits_{i=mid+1}^ki)mid×(n%2==0)+(i=1∑mid−1i)−(i=mid+1∑ki)是可以O(1)O(1)O(1)求出的,我们来看看如何求前面的部分。
可以用状压DP,设fi,sf_{i,s}fi,s表示枚举到AAA的第iii位时状态为sss,sss的二进制位111表示已取过这个数字,000表示没取过这个数字。我们需要预处理数组hvshv_shvs,表示sss的二进制位中有多少个111。
状态转移式如下
fi,s∣(1<<ai−1)={fs−i+ps,aihvs+1<midfs−i×(k%2==0)+ps,aihvs+1=midfs+i+ps,aihvs+1>midf_{i,s|(1<<a_i-1)}= \left\{\begin{matrix} f_s-i+p_{s,a_i} \qquad\qquad\qquad\qquad \ \ hv_s+1<mid \\ f_s-i\times(k\%2==0)+p_{s,a_i} \qquad hv_s+1=mid\\ f_s+i+p_{s,a_i} \qquad\qquad\qquad\qquad \ \ hv_s+1>mid \end{matrix}\right.fi,s∣(1<<ai−1)=⎩⎨⎧fs−i+ps,ai hvs+1<midfs−i×(k%2==0)+ps,aihvs+1=midfs+i+ps,ai hvs+1>mid
其中fi,s∣(1<<ai−1)f_{i,s|(1<<a_i-1)}fi,s∣(1<<ai−1)与后面的部分取max\maxmax。
下面来解释一下ppp是什么。因为在将111到kkk内的数移到一段后,内部还要调整。根据冒泡排序的原理,若要用最少的操作次数排好序,每个数对操作次数的贡献为在它之前比他大的数的个数。ps,ip_{s,i}ps,i表示在sss中二进制位数大于iii且该位为111的数量,在转移式中表示加入这个元素的贡献。
求出fff后,加上mid×(n%2==0)+(∑i=1mid−1i)−(∑i=mid+1ki)mid\times(n\%2==0)+(\sum\limits_{i=1}^{mid-1}i)-(\sum\limits_{i=mid+1}^ki)mid×(n%2==0)+(i=1∑mid−1i)−(i=mid+1∑ki)即为答案。
时间复杂度为O(n⋅2k)O(n\cdot2^k)O(n⋅2k)。
code
#include<bits/stdc++.h>
using namespace std;
int n,k,mid,ans,a[205],v[20],hv[1<<16],p[1<<16][20],f[1<<16];
void pd(int now){f[now]=1000000000;int s=0;for(int i=k;i>=1;i--){p[now][i]=s;s+=v[i];}hv[now]=s;
}
void dfs(int t,int now){if(t<k) dfs(t+1,now);else pd(now);now+=(1<<t-1);v[t]=1;if(t<k) dfs(t+1,now);else pd(now);v[t]=0;
}
int main()
{scanf("%d%d",&n,&k);mid=(k+1)/2;for(int i=1;i<=n;i++){scanf("%d",&a[i]);}dfs(1,0);f[0]=0;for(int i=1;i<=n;i++){for(int s=(1<<k)-1;s>=0;s--){if(s&(1<<a[i]-1)) continue;int t=s|(1<<a[i]-1);if(hv[s]+1<mid) f[s|t]=min(f[s|t],f[s]-i+p[s][a[i]]);else if(hv[s]+1==mid) f[s|t]=min(f[s|t],f[s]-i*(k%2==0)+p[s][a[i]]);else f[s|t]=min(f[s|t],f[s]+i+p[s][a[i]]);}}ans=f[(1<<k)-1];if(k%2==0) ans+=mid;ans=ans+(mid)*(mid-1)/2-(k-mid)*(k+mid+1)/2;printf("%d",ans);return 0;
}