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;
}
posted @ 2025-06-13 16:10  cbbdhz  阅读(49)  评论(0)    收藏  举报