首页 > 其他分享 >[ARC105C] Camels and Bridge 题解

[ARC105C] Camels and Bridge 题解

时间:2024-07-27 22:39:43浏览次数:16  
标签:ARC105C Bridge int 题解 sum rd LF LL dis

[ARC105C] Camels and Bridge 题解

出自梦熊比赛后,梦熊比赛出原题了,忘周知。
也许更好的阅读体验

思路

全排列,差分约束,二分。

全排列

\(n \leq 8\) ,且要指定顺序,易想到用全排列枚举所有状态。

差分约束

在全排列之后,需要求得每种状态的最短距离。定义所有骆驼的编号的集合为 \(S\) ,所有路的部分的编号的集合为 \(E\),定义数组 \(sum,dis\) , \(sum_i\) 表示 \(\sum_{j = 1}^ia_j\) , \(dis_i\) 表示从起点到点 \(i\) 的最短距离, 则对于每对 \(i, j(i,j \in S, i \lt j)\) ,应该有若 \(sum_j - sum_{i - 1} \geq v_k\) ,则 \(dis_j - dis_i \geq l_k(k \in E)\) 。 转换一下,即若\(sum_j - sum_{i - 1} \geq v_k\) ,则 \(dis_i + l_k \leq dis_j(k \in E)\) , 很明显的差分约束条件,跑差分约束就行。

二分

跑差分约束需要建边。
对每个路的部分按 \(v\) 从小到大排序,对于每个 \(dv = sum_j - sum_{i - 1}\), 二分最大的 \(v_k \lt dv\) , 此时用所有 \(i(1 \leq i \leq k)\) 建边等效与用最大的 \(l_i\) 建边。用前缀 max 可以 \(O(1)\) 的建边。

总时间复杂度为 \(O(n!n^2\log m + m\log m)\)

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
typedef long long LL;

using namespace std;

const int N = 10, M = 1e5 + 5;

#define mid (l + r >> 1)
#define pu puts("====================");
#define LF(i, __l, __r) for (int i = __l; i <= __r; i++)
#define RF(i, __r, __l) for (int i = __r; i >= __l; i--)

int temp[10] = {1, 2, 3, 4, 5, 6, 7, 8};
int head[N], nxt[N * N], ver[N * N];
struct node{ LL l, v; } rd[M];
LL a[N], Max, Min = 1e18;
LL PMax[M], ans = 1e18;
LL edge[N * N], sum[N];
int ind[N], n, m, ts = 1, tot = 1;
queue<LL> que;
LL dis[N];

void add(int u, int v, LL w) {
    ver[++tot] = v, edge[tot] = w;
    nxt[tot] = head[u], head[u] = tot;
}

void Init() {
    tot = 1;
    memset(dis, 0, sizeof(dis));
    memset(ind, 0, sizeof(ind));
    memset(head, 0, sizeof(head));
    memset(ver, 0, sizeof(ver));
    memset(nxt, 0, sizeof(nxt));
    memset(edge, 0, sizeof(edge));
}

bool cmp(node a, node b) { return a.v < b.v; }

void topo() {
    LF(i, 1, n) if (!ind[i]) que.push(i);
    
    while (que.size()) {
        LL u = que.front();
        que.pop();
        for (int i = head[u]; i; i = nxt[i]) {
            int v = ver[i]; LL w = edge[i];
            dis[v] = max(dis[v], dis[u] + w);
            ind[v]--;
            if (!ind[v]) que.push(v);
        }
    }
}

int main() {
    scanf("%d%d", &n, &m);
    
    LF(i, 1, n) {
        scanf("%d", &a[i]);
        Max = max(a[i], Max);
    }

    LF(i, 1, m) {
        scanf("%d%d", &rd[i].l, &rd[i].v);
        Min = min(rd[i].v, Min);
    }

    if (Max > Min) { puts("-1"); return 0; }

    LF(i, 1, n) ts *= i;
    sort(rd + 1, rd + m + 1, cmp);
    LF(i, 1, m) { PMax[i] = max(PMax[i - 1], rd[i].l); }

    LF(i, 1, ts) {
        Init();
        LF(i, 1, n) sum[i] = sum[i - 1] + a[temp[i - 1]];

        LF(i, 1, n) LF(j, i + 1, n) {
            LL v = sum[j] - sum[i - 1];
            LL l = 1, r = m, c = -1;

		    while (l <= r) {
			    if (rd[mid].v < v) l = (c = mid) + 1;
			    else r = mid - 1;
		    }
		
		    if (c == -1) continue;
            add(i, j, PMax[c]);
            ind[j]++;
        }
        topo();
        ans = min(ans, dis[n]);
        next_permutation(temp, temp + n);
    }
    printf("%lld", ans);
    return 0;
}

标签:ARC105C,Bridge,int,题解,sum,rd,LF,LL,dis
From: https://www.cnblogs.com/faruzan/p/18327643

相关文章

  • ABC 364 F - Range Connect MST 题解
    一副扑克牌,去掉1到K,剩下就是我,赛后十秒过,我是joker。......
  • CF613E Puzzle Lover 题解
    Description给定一个\(2\timesn\)的矩阵,每个位置上有一个小写字母。有一个长度为\(k\)的小写字符串\(w\),询问矩阵中有多少条有向路径满足以下条件:路径上的字母连起来恰好为\(w\)。不多次经过同一个位置。只能向上下左右四个方向走。\(n,k\le2\times10^3\),答案......
  • IOI2022 邮局 加强版 题解
    [IOI2000]邮局加强版题解考虑动态规划,设\(f_{i,j}\)为经过了\(i\)个村庄,正在建第\(j\)​个邮局的最优距离。以及\(w_{i,j}\)表示区间\([i,j]\)​内建一个邮局时的距离总和。\(a\)数组表示每个村庄的坐标编号。朴素版状态转移方程:\[f_{i,j}=\min(f_{i,j},f_{k,j......
  • 07-25 题解
    07-25题解原题出处(按顺序):CF1556ECF1234FP9746CF1316EP3651CF17CCF1842HA转化:括号序列如果\(a_i\>b_i\),则有\(a_i-b_i\)个左括号如果\(a_i\<b_i\),则有\(b_i-a_i\)个右括号(第一个+1的位置一定在第一个-1的位置的左侧,所以情况一用左括号......
  • 第二次测试部分题解 (c,d,g)
    c-一个欧拉函数模板题 1#include<iostream>2usingnamespacestd;34intmain()5{6intn;7cin>>n;8intr=n;9for(inti=2;i*i<=n;i++)10{11if(n%i==0)12{13r......
  • 第二次测试部分题解
    A——暴力枚举计数就好了,可以参考这段代码#include<bits/stdc++.h>usingnamespacestd;#definelllonglong#definemod100003#defineMAN1000100charstr[10];intans;voidok(){ ans=0; intlen=0; for(inti=0;str[i]!='\0';i++) len++; if(l......
  • ABC260F 题解
    题面根据题目描述,原图为二分图,设两侧点集为\(S,T\),大小为\(s,t(s\le3\times10^5,t\le3\times10^3)\)。注意到有四元环当且仅当\(T\)中存在一个点对\((a,b)\)同时和\(S\)中的某两个点连边。可以先考虑暴力,一种想法是:考虑枚举\(S\)中的点\(c\),设和\(c\)连边的点......
  • ABC263F 题解
    题面注意到把对局在图上表示出来是一颗满二叉树(叶节点为选手,其他点为对局),可以考虑树形dp。设\(x\)为\([l_x,r_x]\)之间选手的比赛,且该节点到叶子结点距离\(d_x\)。设\(f(x,p)\)表示胜者为\(p\)的最大钱数,有转移:\[\begin{aligned}f(x,p)&=f(lson(x),p)+g(rson(x))+a......
  • ABC262F 题解
    题面把“移动\(a_n\)至数列头”称为rotate,删除一项称为erase。因为要求字典序最小,所以可以逐位贪心。考虑一个数\(a_i\)怎么变成第一个数:使用\(n-i\)次rotate/erase,再rotate一次。删除或移动原来的\(a_{i+1}\sima_n\),再移动原来的\(a_i\)(逐步移动到数列尾,再ro......
  • ABC261F 题解
    题面注意到如果两个球\(i,j\)有\(i<j,x_i>x_j\),那么这两个球一定会交换。所以要交换\(x\)的逆序对数次。但是相同颜色交换没有代价,所以答案是\(x\)的逆序对数减去满足\(c_i=c_j,i<j,x_i>x_j\)的\((i,j)\)对的数量。可以对每个\(j\)都求一遍满足\(c_i=j\)的\(......