abc292[AtCoder Beginner Contest 292] 题解

写点题目转换下心情吧

A-CAPS LOCK

大水题

B-Yellow and Red Card

大水题

C-Four Variables

给定一个数N,问有多少个有序正数数组(A,B,C,D),满足A×B+C×D=N

这题荒芜的大脑拒绝思考,看着复杂度不超,写了O(NN)结束了。思想很简单,就是把N分成两个正整数x,y,再O(N)找因数,最后把x,y的因数数量相乘。

知道有O(NlogN)的算法,但是瞬间能写出来的只有这个简单版的了,要反思()

int n;
const int N = 2e5 + 5;
int a[N];

int getNum(int x){
    if (a[x] != 0) return a[x];
    int num = 0;
    for (int i = 1;i * i <= x; ++i){
        if (x % i == 0){
            int j = x / i;
            num++;
            if (i != j) num++;
        }
    }
    return a[x] = num;
}

int main(void){
    cin >> n;
    ll sm = 0;
    for (int i=1;i<n;++i){
        int t1 = getNum(i);
        int t2 = getNum(n - i);
        sm = sm + 1LL * t1 * t2;
    }
    cout << sm << endl;
    return 0;
}

那现在回忆一下O(logN)int getNum(int x)吧,冷静下来想想直接写个类似埃式筛的东西就可以。

void init(){
    for (int i=1;i<=n;++i){
        for (int j=1;1LL * i * j <= n;++j){
            f[i * j]++;
        }
    }
}

D-Unicycliv Components

给定一个n个结点m条边的无向图,问是否每个连通块都满足它的点数和边数相同。

嗯……这题一开始看错题目了,然后耽误了很久写的很麻烦。后面发现对不上样例(典)然后发现这题实际的题意挺简单的。正常查连通块有多少点,然后累加它们的度di,那么连通块边数就等于di2。图论稀碎的我也就这点本事了qaq

int n, m;
const int N = 2e5 + 10, M = 2e5 + 10;
int deg[N];
vector<int> ve[N];
int edges = 0, vertices = 0;
bool vis[N];

void dfs(int x){
    int len = ve[x].size();
    vis[x] = true, vertices++, edges += deg[x];
    for (int i : ve[x]){
        if (!vis[i]) dfs(i);
    }
}

int main(void){
    int u, v;
    cin >> n >> m;
    for (int i=1;i<=m;++i){
        cin >> u >> v;
        deg[u]++, deg[v]++;
        ve[u].push_back(v), ve[v].push_back(u);
    }
    for (int i=1;i<=n;++i){
        vertices = edges = 0;
        if (!vis[i]) dfs(i);
        if (vertices << 1 != edges){
            cout << "No" << endl;
            return 0;
        }
    }
    cout << "Yes" << endl;
    return 0;
}

E-Transitivity

给定一个n个结点m条边的有向简单图,对于任意一个三元组(a,b,c),可执行操作x:若存在边ab,存在边bc,且不存在边ac,那么就可以手动加上ac这条边。问最少要加多少条边才能使得无法再执行该操作。

数据范围:3N2000;0M2000;1ui,viN;uivi;ij,(ui,vi)(uj,vj)

我当时的思路可谓是经典的错误,标准的零分。把整张图分为一个一个连通块,然后一旦出现可以执行操作x的三元组,就证明整个连通块都可以执行这个操作直至变成完全图。(然后轻易举出了反例:

abcd;efgd。这样的话ag之间是不会有有向边的。然后就陷入了“嘶,这样的有向边算不算连通块?”“话说这种东西叫连通块吗,我怎么进一步分割?”等等的错误思想中。实际上再从源头进一步想想,就可以知道这个结论:如果在原图中x可最终抵达y,那么一定可以添加(或者本来存在)xy这条边。

本来还在想怎么优化,一抬头看到N×M=4e6,乐。E题好简单,我真是猪鼻orz

int n, m;
const int N = 2000 + 10;
vector<int> ve[N];
bool vis[N];
int vertices = 0;

void init(){
    for (int i=1;i<=n;++i){
        vis[i] = false;
    }
    vertices = -1;
}

void dfs(int x){
    vis[x] = true, vertices++;
    int xlen = ve[x].size();
    for (int i : ve[x]){
        if (!vis[i]) dfs(i);
    }
}

int main(void){
    cin >> n >> m;
    int u, v;
    for (int i=1;i<=m;++i){
        cin >> u >> v;
        ve[u].push_back(v);
    }
    ll sm = 0;
    for (int i=1;i<=n;++i){
        init();
        dfs(i);
        sm += vertices;
    }
    cout << sm - m << endl;

    return 0;
}

F-Regular Triangle Inside a Rectangle

有一个矩形,边长为正整数A,B。在矩形里放一个等边三角形,问等边三角形最大的边长是多少。

  • 数据范围:1A,B1000;

  • 数据精度要求:109

  • 时间要求:2s

我的小学生数学想法:从长方形的某个顶点出发,印两条夹角为60°的射线,和矩形相交,那么最短的一条交线就是等边三角形的边长。

image-20230309130229057

首先,这个最大的等边三角形,一定会有两个顶点都在矩形边上,不然一定可以找到一个更大的。又大边对大角,小边对小角。l3所对的角度是60°,三角形内角和180°,那l1,l2肯定有一条所对的角度小于等于60°,也就是这两条射线的交线中的一条肯定是最小的边长,l3不可能是最小的那条边,不需要考虑。

l1=A×secα,l2=B×secβ

α+β=30

题目要求精度109,然后cosx范围是[0,1]嘛,这就30°,分成1e8还不拿下?嗯……然后1e8刚好超时几十ms,然后5e7就有两个点wa了,经过几次尝试发现8e7过了()

然后看了题解之后发现,啊哈哈,对哦,这题可以二分写,然后写了半天二分没弄懂题目什么意思orz,为什么就检查了一个sinθA/l,cosθB/l,0θ30°啊,至少不是得检查两条边吗qaq(现在也没搞懂题解一到底在写啥)最后含泪写了三分AC了

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pi acos(-1.0)
#define ZERO 1e-15

int A, B;
const int M = 8e7;
double d = 30.0 * pi / 180;

int main(void){

    cin >> A >> B;
    if (A > B) swap(A, B);
    double l = 0, r = d, m1, m2, res = -1;
    while (r - l > ZERO){
        double m1 = l + (r - l) / 3;
        double m2 = l + (r - l) / 3 * 2;

        double len1 = min(A / cos(m1), B / cos(d - m1));
        double len2 = min(A / cos(m2), B / cos(d - m2));
        if (len1 > len2){
            r = m2, res = len1;
        }
        else{
            l = m1, res = len2;
        }
    }

    cout << fixed << setprecision(15) << res << endl;

    return 0;
}

看不懂第一个editorial,好烦躁0.0,直接来数学方法:

假设A为短边,B为长边,θA和三角形边l的夹角

  • A=B,显然θ=15°

  • ba很多时,那么这时等边三角形是被短边限制住的,最大的可以画的三角形就是以短边为高的等边三角形。故b最小也要是Asin60°=2A3

    因此,当B2A3时,θ=30°

  • A<B<2A3时,l=Bcos(30°θ)=Acosθ

化简得tanθ=2BA3

sec2θ=1+tan2θ=443BA+4B2A2

cosθ=A2A23AB+B2

l=Acosθ=2A23AB+B2

代码如下:

int A, B;
double d = pi / 180.0;

int main(void){

    cin >> A >> B;
    if (A > B) swap(A, B);
    double res = -1;
    if (A == B){
        res = A / (cos(15 * d));
    }
    else if (B >= 2.0 * A / sqrt(3)) {
        res = A / (cos(30 * d));
    }
    else{
        res = 2.0 * sqrt(A*A - sqrt(3)*A*B + B*B);
    }

    cout << fixed << setprecision(15) << res << endl;

    return 0;
}
posted @   跳岩  阅读(163)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示