第二十次CCF计算机软件能力认证

A. 检测点查询

题意

n n n个点中距离关键点最近的三个点。
若距离相同,则取编号小的。
3 ≤ n ≤ 200 , 0 ≤ ∣ x ∣ , ∣ y ∣ ≤ 200 3\le n\le 200,0\le|x|,|y|\le200 3n200,0x,y200

题解

分别记录最小值,次小值,第三小值即可。
时间复杂度 O ( n ) O(n) O(n)

#include <bits/stdc++.h>
#define sqr(x) ((x) * (x))
using namespace std;
typedef pair<int, int> Pii;
int n;
struct Point { int x, y; } p, q;
Pii m1 = {INT32_MAX, 0}, m2 = m1, m3 = m1;
inline int dis2(Point a, Point b) { return sqr(a.x - b.x) + sqr(a.y - b.y); }
inline void Ins(Pii x) {
    if (x < m1) m3 = m2, m2 = m1, m1 = x;
    else if (x < m2) m3 = m2, m2 = x;
    else if (x < m3) m3 = x;
}
int main() {
    scanf("%d%d%d", &n, &q.x, &q.y);
    for (int i = 1; i <= n; ++i)
        scanf("%d%d", &p.x, &p.y), Ins({dis2(p, q), i});
    printf("%d\n%d\n%d", m1.second, m2.second, m3.second);
    return 0;
}

B. 风险人群筛查

题意

给定一个矩形左下角和右上角的坐标。
n n n个人,给定这 n n n个人在 1 ∼ t 1\sim t 1t时刻的坐标。
求有多少人某时刻在出现矩形内;求有多少人至少连续 k k k个时刻在矩形内(边界也算)。
1 ≤ n ≤ 20 , 1 ≤ k ≤ t ≤ 1 0 3 1\le n\le20,1\le k\le t\le10^3 1n20,1kt103

题解

第一问直接判断;第二问判断每个人在矩形内的最长连续时间是否大于等于 k k k即可。
时间复杂度 O ( n t ) O(nt) O(nt)

#include <bits/stdc++.h>
using namespace std;
int n, k, t, Ans1, Ans2;
struct Point {
    int x, y;
    inline void init() { scanf("%d%d", &x, &y); }
    inline bool operator<=(const Point b) { return x <= b.x && y <= b.y; }
} LD, RU, p;
int main() {
    scanf("%d%d%d", &n, &k, &t);
    LD.init(), RU.init();
    while (n--) {
        int flag = 0, maxL = 0, L = 0;
        for (int i = 1; i <= t; ++i) {
            p.init();
            if (LD <= p && p <= RU)
                flag = 1, ++L;
            else
                maxL = max(maxL, L), L = 0;
        }
        maxL = max(maxL, L);
        Ans1 += flag, Ans2 += maxL >= k;
    }
    printf("%d\n%d", Ans1, Ans2);
    return 0;
}

C. 点亮数字人生

题意

给定一个包含 n n n个节点的逻辑电路,每个节点有一个算符( N O T , X O R , A N D , O R , N A N D , N O R \rm NOT,XOR,AND,OR,NAND,NOR NOT,XOR,AND,OR,NAND,NOR),共有 m m m个输入端,每个节点至多有 k k k个输入源。
S S S组询问,给定所有 m m m个输入源的输入值 0 / 1 0/1 0/1 s o s_o so个节点的编号 s 1 , s 2 , . . . , s s o s_1,s_2,...,s_{s_o} s1,s2,...,sso
若逻辑电路存在环,则输出 L O O P \rm LOOP LOOP;否则对于每组询问,求出节点 s 1 , s 2 , . . . , s s o s_1,s_2,...,s_{s_o} s1,s2,...,sso的结果。
Q Q Q组数据。
Q ≤ 5 , n ≤ 500 , k ≤ 5 , m ≤ k n , S ≤ 1 0 4 Q\le5,n\le500,k\le5,m\le kn,S\le10^4 Q5,n500,k5,mkn,S104
样例一对应的逻辑电路:在这里插入图片描述

题解

根据输入的关系建立出相应的有向图(所有的输入源也当成一个点),利用拓扑排序直接求解即可。
时间复杂度 O ( Q S ( n + m ) ) O(QS(n+m)) O(QS(n+m))

#include <bits/stdc++.h>
using namespace std;
const int N = 3000 + 5;
typedef int arr[N];
int n, m, S, Cnt, Loop;
arr in, deg, op, Ans, s_;
vector<int> G[N], input[N];
vector<int> I_[10005];
inline int f(vector<int> input, int op) {
    int y = 0;
    if (!op) return !input[0]; // NOT
    else if (op == 1) {   // XOR
        for (auto x : input)
            y ^= x;
        return y;
    } else if ((op | 1) == 3) { // AND,NAND
        y = input[0];
        for (int i = 1; i < (int)input.size(); ++i)
            y &= input[i];
        return op & 1 ? !y : y;
    } else { // OR,NOR
        for (auto x : input)
            y |= x;
        return op & 1 ? !y : y;
    }
}
inline void Topsort() {
    if (Loop == 1)
        return;
    queue<int> q;
    for (int i = 1; i <= n; ++i)
        deg[i] = in[i], input[i].clear();
    for (int i = n + 1; i <= n + m; ++i)
        q.push(i);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (auto v : G[u]) {
            input[v].push_back(Ans[u]);
            if (!(--deg[v]))
                Ans[v] = f(input[v], op[v]), q.push(v);
        }
    }
    if (Loop == -1) {
        for (int i = 1; i <= n; ++i)
            if (deg[i])
                return (void)(Loop = 1, puts("LOOP"));
        Loop = 0;
    }
    for (int i = 1; i <= Cnt; ++i)
        printf("%d%c", Ans[s_[i]], " \n"[i == Cnt]);
}
inline int GetOP(char *s) {
    if (s[0] == 'O') return 4;
    if (s[0] == 'X') return 1;
    if (s[0] == 'A') return 2;
    if (s[1] == 'A') return 3;
    if (s[2] == 'T') return 0;
    return 5;
}
inline void Solve() {
    for (int i = 1; i <= n + m; ++i)
        in[i] = 0, G[i].clear();
    for (int i = 1; i <= n; ++i) {
        char s[5];
        int u;
        scanf("%s%d", s, &in[i]);
        op[i] = GetOP(s);
        for (int j = 1; j <= in[i]; ++j) {
            scanf("%s", s);
            if (s[0] == 'O')
                sscanf(s, "O%d", &u), G[u].push_back(i);
            else
                sscanf(s, "I%d", &u), G[n + u].push_back(i);
        }
    }
    Loop = -1;
    scanf("%d", &S);
    for (int i = 1; i <= S; ++i) {
        I_[i].resize(m);
        for (int j = 0; j < m; ++j)
            scanf("%d", &I_[i][j]);
    }
    for (int i = 1; i <= S; ++i) {
        for (int j = n + 1; j <= n + m; ++j)
            Ans[j] = I_[i][j - n - 1];
        scanf("%d", &Cnt);
        for (int j = 1; j <= Cnt; ++j)
            scanf("%d", s_ + j);
        Topsort();
    }
}
int main() {
    scanf("%*d");
    while (~scanf("%d%d", &m, &n))
        Solve();
    return 0;
}

D. 星际旅行

题意

给定一个半径为 r r r n n n维球体和 m m m n n n维点。
求每个点到剩下 m − 1 m-1 m1个点的不穿过球体的最短距离之和。
2 ≤ n ≤ 100 , 2 ≤ m ≤ 2000 , 1 ≤ r ≤ 1 0 3 , 0 ≤ ∣ x ∣ , ∣ y ∣ ≤ 1 0 3 2\le n\le100,2\le m\le2000,1\le r\le10^3,0\le |x|,|y|\le10^3 2n100,2m2000,1r103,0x,y103

题解

考虑二维的情况
在这里插入图片描述
其中
θ 1 = ∠ O A C = arcsin ⁡ r ∣ A O ∣ θ 2 = ∠ O B D = arcsin ⁡ r ∣ B O ∣ θ 3 = ∠ A O B = arccos ⁡ ∣ A O ∣ 2 + ∣ B O ∣ 2 − ∣ A B ∣ 2 2 ∣ A O ∣ ∣ B O ∣ θ 4 = ∠ C O D = θ 3 − ( π 2 − θ 1 ) − ( π 2 − θ 2 ) = θ 1 + θ 2 + θ 3 − π \begin{aligned} \theta_1&=\angle OAC=\arcsin\frac{r}{|AO|}\\ \theta_2&=\angle OBD=\arcsin\frac{r}{|BO|}\\ \theta_3&=\angle AOB=\arccos\frac{|AO|^2+|BO|^2-|AB|^2}{2|AO||BO|}\\ \theta_4&=\angle COD=\theta_3-(\frac{\pi}2-\theta_1)-(\frac{\pi}2-\theta_2)=\theta_1+\theta_2+\theta_3-\pi \end{aligned} θ1θ2θ3θ4=OAC=arcsinAOr=OBD=arcsinBOr=AOB=arccos2AOBOAO2+BO2AB2=COD=θ3(2πθ1)(2πθ2)=θ1+θ2+θ3π

d i s ( A , B ) = A C ‾ + C D ⌢ + B D ‾ = ∣ A O ∣ 2 − r 2 + ∣ B O ∣ 2 − r 2 + r θ 4 dis(A,B)=\overline{AC}+\overset{\large\frown}{CD}+\overline{BD}=\sqrt{|AO|^2-r^2}+\sqrt{|BO|^2-r^2}+r\theta_4 dis(A,B)=AC+CD+BD=AO2r2 +BO2r2 +rθ4.
当线段 A B AB AB与圆不相交时,依照上式计算出来的 θ 4 < 0 \theta_4<0 θ4<0,判断一下即可。
注意常数,时间复杂度 O ( n m 2 ) O(nm^2) O(nm2)

#include <bits/stdc++.h>
using namespace std;
const int N = 100 + 5, M = 2e3 + 5;
const double Pi = acos(-1);
int n, m, r, r2;
double dis[M][M];
struct Point {
    int a[N];
    inline void init() {
        for (int i = 1; i <= n; ++i)
            scanf("%d", a + i);
    }
} O, p[M];
#define sqr(x) ((x) * (x))
inline int Len(Point a, Point b) {
    int L = 0;
    for (int i = 1; i <= n; ++i)
        L += sqr(a.a[i] - b.a[i]);
    return L;
}
int main() {
    scanf("%d%d%d", &n, &m, &r);
    O.init();
    r2 = r * r;
    for (int i = 1; i <= m; ++i)
        p[i].init();
    for (int i = 1; i <= m; ++i)
        for (int j = i + 1; j <= m; ++j) {
            double AO2 = Len(p[i], O), BO2 = Len(p[j], O), AB2 = Len(p[i], p[j]),
				   t1 = asin(r / sqrt(AO2)), t2 = asin(r / sqrt(BO2)),
                   t3 = acos((AO2 + BO2 - AB2) / (2 * sqrt(AO2 * BO2))),
                   t4 = t1 + t2 + t3 - Pi;
            if (t4 < 0)
                dis[i][j] = dis[j][i] = sqrt(AB2);
            else
                dis[i][j] = dis[j][i] = sqrt(AO2 - r2) + sqrt(BO2 - r2) + r * t4;
        }
    for (int i = 1; i <= m; ++i)
        printf("%.10lf\n", accumulate(dis[i] + 1, dis[i] + m + 1, 0.0));
    return 0;
}

E. 密信与计数

简要题意

给你一个解码本和一堆单词。
求长度为k的密文:不包含单词为子串,且解密后的明文是由单词组成的。这样的字符串有多少种。
在这里插入图片描述

题解

大佬的口糊题解:

解码本一页很简单
n页就多记一维状态就好了
考虑一页的情况
先把字典翻译回去
得到不超过38个的密文串
对字典建ac自动机
对于ac自动机上每个节点
我们dp
如果走到终止节点就不转移
  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值