A - Jiro

题意

给你AB, AC, BC之间的大小关系,问你ABC的中位数是哪个

大概思路

考虑用最少的特征分别决定其中两种情况,剩下一种情况直接排除法就行

代码

void solve(){
    std::string AB, AC, BC;
    std::cin >> AB >> AC >> BC;

    if (AB == BC) {
        std::cout << 'B';
        return; 
    } else if (AC != BC) {
        std::cout << 'C';
        return;
    } else {
        std::cout << 'A';
        return;
    }
}

B - Taro

题意

n个家庭,按时间线生娃,每生一个就问这个娃是不是“该家庭的第一个男孩?”

大概思路

水题,直接vector记录就行

(Q:为什么不用set?A:n都告诉你了,你还用set,嫌时间复杂度够用,非要挂个log是吗)

代码

void solve(){
    int n, m ;
    std::cin >> n >> m;

    std::vector<bool> ok(n + 1);
    while (m--) {
        int id;
        std::string s;
        std::cin >> id >> s;
        if (s == "M" && !ok[id]) {
            std::cout << "Yes\n";
            ok[id] = 1;
        } else {
            std::cout << "No\n";
        }
    }
}

C - Make Isomorphic

题意

给你两个图,一个模版图G,一个操作用图H,以及操作H的各个边时的代价矩阵。求使得图H同构于图G的最小操作代价和。

两个图同构当且仅当其中一个图的序号存在一个 排列 使得两个图完全相等。

大概思路

抽象的题,第一次ABC差点写不出C。题目数据范围特别小,$n \le 8$,那么我们直接暴力枚举节点的所有排列,判断是否删边或加边即可。

思路不难想,但是实现很有趣。

代码

void solve(){
    int n;
    std::cin >> n;
    //=============数据读入=============//
    std::vector<std::vector<bool>> G(n + 1, std::vector<bool>(n + 1)), H = G;

    int gn;
    std::cin >> gn;
    for (int i = 0; i < gn; i++) {
        int x, y;
        std::cin >> x >> y;
        G[x][y] = G[y][x] = 1;
    }

    int hn;
    std::cin >> hn;
    for (int i = 0; i < hn; i++) {
        int x, y;
        std::cin >> x >> y;
        H[x][y] = H[y][x] = 1;
    }

    std::vector<std::vector<int>> a(n + 1, std::vector<int>(n + 1));
    for (int i = 1; i <= n - 1; i++) {
        for (int j = i + 1; j <= n; j++) {
            std::cin >> a[i][j];
            a[j][i] = a[i][j];
        }
    }
    //=============主逻辑=============//
    i64 ans = 2e18;
    
    std::vector<int> to(n);
    std::iota(to.begin(), to.end(), 0);
    
    do {
        i64 cost = 0;
        for (int i = 1; i <= n - 1; i++) {
            for (int j = i + 1; j <= n; j++) {
                int X = to[i - 1] + 1;
                int Y = to[j - 1] + 1;
                if (H[i][j] ^ G[X][Y]) {//代码核心,当且仅当两个图这对边不一样时,才要进行修改操作
                    cost += a[i][j];
                }
            }
        }
        ans = std::min(ans, cost);
    } while (std::next_permutation(to.begin(), to.end()));//经典next_permutation

    std::cout << ans;
}

D - 1D Country

题意

$n$户人分别住在$x_i$位置,每户有$p_i$人,给出 $q$ 个,每次问住在 $[l,r]$区间的有多少人。

大概思路

树状数组板子题,树状数组秒了(你要硬是想写大线段树,那我也没办法)

代码

template<typename T>
struct BIT {
	std::vector<T> C;
	int n;
	BIT(int n_) {
		C.clear();
		C.resize(n_ + 1);
		n = n_;
	}
	BIT() {}
	BIT(const BIT& bit) {
		n = bit.n;
		C = bit.C;
	}
	T getsum(int x) {//获取[1, x]的和		O(logn)
	    T s = 0;
	    while (x) {
	        s += C[x];
	        x -= (x &- x);
	    }
	    return s;
	}
	void add(int x, T key) {//单点增加x的值	O(logn)
	    while (x <= n) {
	        C[x] += key;
	        x += (x &- x);
	    }
	}
};

void solve(){
    int n;
    std::cin >> n;

    BIT<i64> bit(n + 1);

    std::vector<std::pair<int, int>> a(n);

    for (auto &[x, _] : a) std::cin >> x;
    for (auto &[_, p] : a) std::cin >> p;

    std::vector<int> x(n);
    for (int i = 0; i < n; i++) {
        x[i] = a[i].first;
        bit.add(i + 1, a[i].second);
    }

    int m;
    std::cin >> m;
    while (m--) {
        int l, r;
        std::cin >> l >> r;

        int L = std::lower_bound(x.begin(), x.end(), l) - x.begin();
        int R = std::upper_bound(x.begin(), x.end(), r) - x.begin();

        std::cout << bit.getsum(R) - bit.getsum(L) << "\n";
    }
}