The 2024 ICPC Asia Shenyang Regional Contest (The 3rd Universal Cup. Stage 19: Shenyang) - E

补题链接

在这里插入图片描述

首先不同的地图最多只有16种了,每张地图可以组合的格式是 2 16 2^{16} 216 ,因为同一种地图变成全 1 1 1 的步骤是一样的,那么我们可以这么抽象,把一种不同的地图状态看成二进制的某一位,把一些地图的组合看成是一个点,要求的是最小花费,我们可以用全 1 1 1 的地图作为起点,向外拓展可以到达的点,那么就可以使用最短路求解。
具体的:令 d i s [ x ] dis[x] dis[x] 表示到达 x x x 这个地图状态的最小花费 , x x x 在第 i i i 位是 1 1 1 代表的就是代表有第 i i i 张地图。我们可以定义 t r a n s [ b i t ] [ S ] trans[bit][S] trans[bit][S] 表示 当前有的地图集合是 S S S 进行 b i t bit bit 操作时变成的状态集合 S ′ S' S . b i t bit bit 是题目给的一行,一列等等的操作,具体是把 2 × 2 2\times 2 2×2 的格子从左到右,从上到下设为 1 , 2 , 4 , 8 1,2,4,8 1,2,4,8 ,那么比如说对上面一行操作,那就是一张地图的二进制表示异或上 3 3 3

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using i128 = __int128;
#define int long long 


constexpr int maxn = 1<<16;
constexpr int FULL = 15;
constexpr i64 inf = (1ll<<60);
int trans[16][maxn]; //S经过bit变化会变成什么
i64 dis[maxn];
bool vis[maxn];
vector<pair<int,int>> op; 
int a0,a1,a2,a3;

inline int calc(string &s1,string &s2){
    return (s1[0]=='1'?1 : 0) + 
           (s1[1]=='1'?2 : 0) +
           (s2[0]=='1'?4 : 0) +
           (s2[1]=='1'?8 : 0);
}


void solve(){
    int n;cin>>n;
    string s1,s2;
    int S = 0;
    for(int i = 0;i<n;++i){
        cin>>s1>>s2;
        S |= (1<<calc(s1,s2));
    }
    cout<<dis[S]<<'\n';
}

signed main(){
    ios::sync_with_stdio(0);cin.tie(0);
    int t=1;
    cin>>t>>a0>>a1>>a2>>a3;
    fill(dis,dis+maxn,inf);

    for(int m = 0;m<16;++m){
        for(int S = 0;S<maxn;++S){
            int Y = 0;
            for(int bit = 0;bit<16;++bit){
                if((S>>bit)&1) Y|=(1<<(bit^m));
            }
            trans[m][S] = Y;
        }
    }

    op.emplace_back(1,a0);
    op.emplace_back(2,a0);
    op.emplace_back(4,a0);
    op.emplace_back(8,a0);

    op.emplace_back(3,a1);
    op.emplace_back(12,a1);

    op.emplace_back(5,a2);
    op.emplace_back(10,a2);

    op.emplace_back(15,a3);

    dis[0] = 0;
    priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> q;
    q.emplace(0,0);//d u

    while(!q.empty()){
        auto [d,u] = q.top();
        q.pop();
        if(vis[u]) continue;
        vis[u] = true;
        for(auto &[m,w]:op){
            int v1 = trans[m][u];
            int v2 = trans[m][u|(1<<15)];//全1

            if(dis[v1]>w+dis[u]){
                dis[v1] = w + d;
                q.emplace(dis[v1],v1);
            }

            if(dis[v2]>w+dis[u]){
                dis[v2] = w + d;
                q.emplace(dis[v2],v2);
            }

        }

    }
    while(t--) solve();
    return 0;
}

突然发现之前的代码贴错了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值