[海军国际项目办公室]序列

序列

题面

在这里插入图片描述
在这里插入图片描述

题解

首先我们看到我们的数据范围 k ⩽ 10 k\leqslant 10 k10基本就可以猜到这是一个状压的题目了,而且状态还是 2 k 2k 2k的。然而笔者场上并没想出怎么做,不过怎么这么多人都 A A A了,太离谱了

首先,对于这种区间异或值的,而且还只有 0 , 1 0,1 0,1的,我们可以考虑通过差分转化为单点的异或值。
如果我们要使得点 x x x的值为 1 1 1的话,我们要对点 x x x x + 1 x+1 x+1分别异或上差分值 1 1 1
也就是说,我们要使我们的序列变成目标序列,是等价于将该差分序列变成目标的差分序列的。
我们每次的操作对于一个长度为 a i a_{i} ai的区间异或上 1 1 1,相当于改变两个距离为 a i a_{i} ai的点的差分值。
很明显,当我们更改了两个差分之后,如果有一个位置不合适,我们想将它去掉,也就只会在另外某个地方增加一个,事实上差分值个数并未发生变化,我们在这样一段连续的操作中,差分值为 1 1 1的位置只会有两个。

而我们目标的差分值并不只有 2 2 2个,也就是说,我们需要进行多次操作。
我们每次连续的操作会改变其中两个为 1 1 1的差分值位置。
我们可以通过状压维护我们的差分值的状态为某个状态的最少操作数,很明显我们不可能将说有点都在一起维护,我们可以只维护差分值应该为 1 1 1的位置。
我们的每次操作是通过一系列的操作使得其中两个差分值的状态改变,对于改变两个固定位置的差分值,我们可以先通过 b f s bfs bfs预处理出来。
我们可以先在我们的两个差分位置中固定一个位置,而我们会通过操作,使得其另一个位置发生变化,而另外一个点发生变化的需要的最小操作数的转移,是与最短路差不多的,由于边权都是 1 1 1,我们可以用 b f s bfs bfs的方法转移。
我们只要把每一对数变化的状况都加入我们的状压 d p dp dp即可。

时间复杂度 O ( n 2 2 2 k + n k l ) O\left(n^22^{2k}+nkl\right) O(n222k+nkl)
好丑的时间复杂度呀。

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 10005
#define MAXM (1<<20)+5
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;       
const int INF=0x3f3f3f3f;       
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,k,l,b[15],a[205],dp[2][MAXM],dis[MAXN],d[25],totd,cnt[MAXN];
bool vis[MAXN];
queue<int>q;
void sakura(int s){
	for(int i=1;i<=n+1;i++)dis[i]=INF,vis[i]=0;
	while(!q.empty())q.pop();dis[s]=0;q.push(s);vis[s]=1;
	while(!q.empty()){
		int t=q.front();q.pop();
		for(int i=1;i<=l+l;i++){
			int v=t+a[i];if(v<1||v>n+1||vis[v])continue;
			dis[v]=dis[t]+1;vis[v]=1;q.push(v);
		}
	}
}
signed main(){
	read(n);read(k);read(l);
	for(int i=1;i<=k;i++)read(b[i]),cnt[b[i]]^=1,cnt[b[i]+1]^=1;
	for(int i=1;i<=l;i++)read(a[i]),a[l+i]=-a[i];
	for(int i=1;i<=n+1;i++)if(cnt[i])d[++totd]=i;
	int now=0,las=1;for(int i=1;i<(1<<totd);i++)dp[0][i]=INF;
	for(int i=1;i<totd;i++){
		sakura(d[i]);
		for(int j=i+1;j<=totd;j++){
			swap(now,las);int S=(1<<i-1)|(1<<j-1);
			for(int p=0;p<(1<<totd);p++)
				dp[now][p]=min(dp[las][p],dp[las][p^S]+dis[d[j]]);
		}
	}
	printf("%d\n",dp[now][(1<<totd)-1]<INF-1?dp[now][(1<<totd)-1]:-1);
	return 0;
}

谢谢!!!

posted @ 2021-09-09 22:23  StaroForgin  阅读(11)  评论(0)    收藏  举报  来源