codeforces 995 Snakes
题目链接
https://codeforces.com/contest/2051/problem/G
思路
-
首先一个最简单的思路就是枚举排列,然后求相邻两条蛇最小要分配多少距离,最后取最小就行。
-
然后相邻两条蛇的最小距离可以预处理求能降低一部分复杂度,因为就\(n^2\)个状态。
-
相邻两条蛇最小距离只和和左边的蛇的伸长,和右边蛇的缩短有关。
-
最开始两条蛇距离至少是\(1\),然后随着时间顺序处理和这两条蛇有关的操作。
-
如果左蛇伸长,距离就至少要\(2\)了,右蛇缩短虽然不会改变至少的距离,但之后能抵消一次左蛇的伸长。
-
这一过程就像维护一个\(dis\),左蛇伸长\(dis\)++,右蛇缩短\(dis\)--。
-
定义\(dp[a][b]\)就是左蛇是\(a\),右蛇是\(b\)的最少距离,而\(dp[a][b]\)的值就是\(dis\)的历史最值。
-
但实际上因为是枚举排列是\(n!\)的复杂度,还要把相邻最小距离算一下,总共是\(n*n!\)的复杂度。
-
这部分也要优化,定义\(nm[i][j][s]\)为填到了\(i\)位置最后一个位置是\(j\)蛇,\(s\)表示哪些蛇已经用了。
-
会爆内存,压掉第一维\(i\)填到哪个位置。
-
转移的话就是先枚举填到哪个位置。
-
再枚举尾巴\(l\)是谁,再枚举状态\(s\)。再枚举下一个填\(j\)蛇。
-
这个状态\(s\)要求\(1\)的个数是\(i\),且\(l\)蛇用了而\(j\)蛇没用。
-
转移就是\(nm[j][s|(1<<(j-1)]=min(nm[j][s|(1<<(j-1)],nm[l][s]+dp[l][j]);\)
-
最后找出最小的\(nm[i][(1<<n)-1]\)+最后一条蛇能伸长的长度就是答案。
-
第一部分大概是\(n*q\),第二部分大概是\(n^2*(1<<n)\) 。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=21;
vector<vector<int>>v1(N);//正的
vector<vector<int>>v2(N);//负的
int dp[N][N];//任意两个人之间的最小距离
int nm[N][(1<<20)];//填了几个,最后一个是谁,还有哪些可选。
vector<vector<int>>sta(N);
signed main(){
#ifdef ONLINE_JUDGE
#else
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
ios::sync_with_stdio(false);cin.tie(0);
int n,q;cin>>n>>q;
for(int i=1;i<=q;i++){
int x;char op;cin>>x>>op;
if(op=='+'){
v1[x].push_back(i);
}else v2[x].push_back(i);
}
for(int a=1;a<=n;a++)for(int b=1;b<=n;b++){
if(a==b)continue;dp[a][b]=1;
int dis=1;int p1=0;int p2=0;
while(p1<v1[a].size()||p2<v2[b].size()){
if(p1==v1[a].size()){
dis--;p2++;
}else if(p2==v2[b].size()){
dis++;p1++;
}else if(v1[a][p1]<v2[b][p2]){
dis++;p1++;
}else{
dis--;p2++;
}
dp[a][b]=max(dp[a][b],dis);
}
}
memset(nm,0x3f,sizeof(nm));
int all=(1<<n)-1;
for(int s=0;s<=all;s++){
int t=__builtin_popcount(s);
sta[t].push_back(s);
}
for(int i=1;i<=n;i++){
nm[i][(1<<(i-1))]=1;
}
for(int i=1;i<n;i++){
for(int l=1;l<=n;l++)//上个是谁
for(auto s:sta[i]){
for(int j=1;j<=n;j++){
if((s>>(j-1))&1||(s>>(l-1))==0)continue;
int ns=s|(1<<(j-1));
nm[j][ns]=min(nm[j][ns],nm[l][s]+dp[l][j]);
}
}
}
int res=2e9;
for(int i=1;i<=n;i++){
res=min(res,nm[i][all]+(int)v1[i].size());
}cout<<res<<endl;
}

浙公网安备 33010602011771号