AtCoder ABC197

文章介绍了四个ATCoder编程题目:C-ORXOR中的状态压缩枚举,D-Opposite中的坐标旋转,E-Traveler中的两端点DP模型,以及F-ConstructaPalindrome中的最短路径问题。涉及了动态规划、矩阵操作和图论算法的应用。
摘要由CSDN通过智能技术生成

本期难度适中,比起前几期的FFT和网络流要容易一些,但是需要仔细思考

C - ORXOR

n=20,可以暴力
把数中间的隔板进行状态压缩枚举

# -*- coding: utf-8 -*-
# @time     : 2023/6/2 13:30
# @file     : atcoder.py
# @software : PyCharm

import bisect
import copy
import sys
from itertools import permutations
from sortedcontainers import SortedList
from collections import defaultdict, Counter, deque
from functools import lru_cache, cmp_to_key
import heapq
import math
sys.setrecursionlimit(100010)


def check(arr_list):
    ret = 0
    for arr in arr_list:
        temp = 0
        for x in arr:
            temp |= x
        ret ^= temp
    return ret


def main():
    items = sys.version.split()
    fp = open("in.txt") if items[0] == "3.10.6" else sys.stdin
    n = int(fp.readline())
    a = list(map(int, fp.readline().split()))
    ans = 1 << 60
    for mask in range(1 << n):
        b = []
        temp = []
        for i in range(n):
            temp.append(a[i])
            if (mask >> i) & 1:
                b.append(temp)
                temp = []
        if len(temp) > 0:
            b.append(temp)
        ans = min(ans, check(b))
    print(ans)


if __name__ == "__main__":
    main()

D - Opposite

将坐标为 x , y x,y x,y的点逆时针旋转 θ \theta θ公式
[ x 1 y 1 ] = [ c o s θ − s i n θ s i n θ c o s θ ] [ x 0 y 0 ] \begin {bmatrix} x_1 \\ y_1 \end{bmatrix} = \begin {bmatrix} cos\theta &-sin\theta \\ sin\theta & cos\theta \end{bmatrix} \begin {bmatrix} x_0 \\ y_0 \end{bmatrix} [x1y1]=[cosθsinθsinθcosθ][x0y0]
其实就是欧拉公式在xy坐标系下的变形

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <map>
#include <cmath>
#include <set>
#include <vector>
#include <queue>
#include <unordered_map>
#include <algorithm>
#define LT(x) (x * 2)
#define RT(x) (x * 2 + 1)

using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
const ll inf = ll(1e15);
const ld pi = 3.1415926535897932384626;


int n;


int main() {
    //freopen("in.txt", "r", stdin);
    scanf("%d", &n);
    int x0, y0, xn, yn;
    scanf("%d%d%d%d", &x0, &y0, &xn, &yn);
    ld dx0, dy0, dxn, dyn;
    dx0 = x0, dy0 = y0, dxn = xn, dyn = yn;
    ld cx = (dx0 + dxn) / 2, cy = (dy0 + dyn) / 2;
    ld x = dx0 - cx, y = dy0 - cy;
    ld sinx = sin(2.0 * pi / n), cosx = cos(2.0 * pi / n);

    ld nx = x * cosx - y * sinx + cx, ny = x * sinx + y * cosx + cy;
    printf("%.8Lf %.8Lf\n", nx, ny);
    return 0;
}

E - Traveler

因为按照颜色顺序,每次必须取完每种颜色最小值与最大值 [ L , R ] [L,R] [L,R]之间的所有点,从 L L L或者 R R R进入下一种颜色
显然是个两端点dp的模型
设dp[i][0]是第i种颜色取完之后从L出去(最后一个点是L)的cost最小值,dp[i][1]是从R出去的最小值

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <map>
#include <cmath>
#include <set>
#include <vector>
#include <queue>
#include <unordered_map>
#include <algorithm>
#define LT(x) (x * 2)
#define RT(x) (x * 2 + 1)

using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<ll> vi;
const ll inf = ll(1e15);
const ld pi = 3.1415926535897932384626;


int n;
vi balls[200020];
ll dp[200020][2];


int main() {
    //freopen("in.txt", "r", stdin);
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) {
        int x, c;
        scanf("%d%d", &x, &c);
        balls[c].push_back(x);
    }
    for (int i = 0; i <= n; ++i) {
        sort(balls[i].begin(), balls[i].end());
    }
    dp[0][0] = dp[0][1] = 0;
    balls[0] = { 0 };
    vi last = balls[0];
    for (int i = 1; i <= n; ++i) {
        if (balls[i].size() == 0) {
            dp[i][0] = dp[i - 1][0], dp[i][1] = dp[i - 1][1];
        }
        else {
            int m = balls[i].size(), lm = last.size();
            ll l0 = last[0], r0 = last[lm - 1], l1 = balls[i][0], r1 = balls[i][m - 1];
            dp[i][0] = min(abs(l0 - r1) + dp[i - 1][0], abs(r0 - r1) + dp[i - 1][1]) + r1 - l1;
            dp[i][1] = min(abs(l0 - l1) + dp[i - 1][0], abs(r0 - l1) + dp[i - 1][1]) + r1 - l1;
            last = balls[i];
        }
    }
    ll ans = min(abs(last[0]) + dp[n][0], abs(last[last.size() - 1]) + dp[n][1]);
    printf("%lld\n", ans);
    return 0;
}

F - Construct a Palindrome

把问题改成两边同时出发汇合。由于两边是从 ( 1 , n ) (1,n) (1,n)出发的,设当前的状态为 ( i , j ) (i,j) (i,j),从状态 ( i 0 , j 0 ) (i_0,j_0) (i0,j0)转移到 ( i 1 , j 1 ) (i_1,j_1) (i1,j1)需要满足边 i 0 i 1 i_0i_1 i0i1和边 j 0 j 1 j_0j_1 j0j1是相同字母。求到 ( t , t ) (t,t) (t,t)或者 ( s , t ) (s,t) (s,t)有边的最短路径。修改普通的bfs算法,在转移状态入队列的时候枚举字母即可。

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <map>
#include <cmath>
#include <set>
#include <vector>
#include <queue>
#include <unordered_map>
#include <algorithm>
#define LT(x) (x * 2)
#define RT(x) (x * 2 + 1)

using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
const ll inf = ll(1e15);
const ld pi = 3.1415926535897932384626;

int n, m;
vi g[1002][26];
int f[1002][1002];
bool w[1002][1002];


int main() {
    //freopen("in.txt", "r", stdin);
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int u, v;
        char c;
        cin >> u >> v >> c;
        int p = c - 'a';
        g[u][p].push_back(v);
        g[v][p].push_back(u);
        w[u][v] = w[v][u] = 1;
    }
    memset(f, 0xff, sizeof(f));
    f[1][n] = 0;
    int ans = 1 << 30;
    queue<pii> qu;
    qu.push({ 1, n });
    while (!qu.empty()) {
        pii c = qu.front();
        qu.pop();
        int u0 = c.first, u1 = c.second;
        if (u0 == u1) {
            if (f[u0][u1] * 2 <= ans - 1)
                ans = f[u0][u1] * 2;
        }
        if (w[u0][u1]) {
            ans = min(ans, f[u0][u1] * 2 + 1);
        }
        for (int p = 0; p < 26; ++p) {
            for (int v0 : g[u0][p]) {
                for (int v1 : g[u1][p]) {
                    if (f[v0][v1] == -1) {
                        f[v0][v1] = f[u0][u1] + 1;
                        qu.push({ v0, v1 });
                    }
                }
            }
        }
    }
    if (ans > 200000) ans = -1;
    printf("%d\n", ans);
    return 0;
}

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值