长为n(n<=22)的序列a和b,第i个数分别对应ai和bi(1<=ai<=1e15,1<=bi<=1e15)
你可以执行以下两种操作任意次:
1. 将a序列分成若干段,然后可以任意重排这些段,
如果将a序列分成了x段,则代价是(x-1)*c,
比如,可以分成a1,a2a3,a4a5a6,然后重排为a2a3,a4a5a6,a1,代价是2*c
2. 选择a的任意一个位置,对其加k,代价是k的绝对值
求最小的总代价,使得a和b序列完全相等
liouzhou101 & 官方题解
乱搞AC
首先,考虑如果a的位置和b的位置在排列的位置上一一映射上了,
那么,比如a[i]和b[j]映射上了,那么通过第二种操作相等的额外代价就是abs(a[i]-b[j])
也就是说,这个分成x段并重排的操作只需要进行一次,剩下的都用第二种操作
所以,状压这个第一种操作的顺序
然后发现,如果A|BC|DE被重排成了DE|BC|A,
也就是B在新序列的位置和A的位置不再前后相邻,D在新序列的位置和A的位置不再前后相邻
所以,一个比较自然的做法是,增序考虑选a的过程
假设当前选到了第i个,那么S集合内1的个数一定是i,
选择a的第i个的时候,需要考虑a的第i-1个选的是什么,从而判断二者是否前后相邻
于是就有,dp[S][i]表示(当前选了a序列前bit[S]个数),当前选择的b的集合是S,
当前a的最后一个数对应的b中的数选的是第i个时,二者只考虑这些数时完全相同的最小代价
那么转移就是如果上一个选的和当前选的前后相邻,就不额外创建一段
否则需要新起一段,加上c的代价,暴力这样做的复杂度
然后发现,假设前驱转移有x个,那么只有一个是不额外创建的,x-1个是额外创建的
不妨松弛一下答案,
也就是当成x个是额外创建的,1个是不额外创建的,
维护一下这x个前驱的最小值mn
用mn更新一次额外创建的答案,用这一个前驱更新一次不额外创建的答案,转移就O(1)了
复杂度
交的时候,发现MLE了,因为空间也开了
时间给了2.8s,空间给了512M,但是22*2的22次方大概是700多M,long long改不了
把long long改成动态开的指针和回收结果TLE了
然后考虑把dp状态改成可回收的节点,用的时候取一个节点,不用的时候放回去
把空间压了压,相当于根据位从少到多bfs,
少的位的状态用过之后就从队列里干掉,达到复用空间的效果,类似循环队列
但是这么做肯定不是题目想让的样子,于是看了官方题解&别人的提交
dp[S]表示当前选的集合是S,一次决策一段,把一段对应的代价c加上去
也就是取一段连续的a的区间[l,r],往b当前的集合中,没取并且也连续的一段区间里放
由于长为k的转移会出现次,所以复杂度还是的
手玩的时候没细想,以为多一个n
由于状态是从0开始拓展的,也就是拓展第一段的时候也会多算一个c,所以最终答案减c
#include
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<>j&1;
}
int main(){
sci(n),scll(c);
rep(i,0,n-1){
scll(a[i]);
}
rep(i,0,n-1){
scll(b[i]);
}
memset(dp,0x3f,sizeof dp);
int up=(1<>j&1)bit++;
}
rep(j,0,n-1){
if(!has(i,j)){
ll v=dp[i]+c;
int nex=i,x=0;
while(j+x
#include
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<q;
void upd(ll &x,ll y){
x=min(x,y);
}
int f(int v){
if(~id[v])return id[v];
int x=q.back();
q.pop_back();
memset(dp[x],0x3f,sizeof dp[x]);
return id[v]=x;
}
void g(int x){
q.push_back(id[x]);
}
bool has(int i,int j){
return i>>j&1;
}
int main(){
sci(n),scll(c);
rep(i,0,n-1){
scll(a[i]);
}
rep(i,0,n-1){
scll(b[i]);
}
memset(id,-1,sizeof id);
int up=(1<=0 && has(i,j-1)){
upd(dp[f(i|(1<