AtCoder Beginner Contest 168题解

这里写目录标题

  • A - ∴ (Therefore)
    • 代码
  • B - ... (Triple Dots)
    • 代码
  • C - : (Colon)
    • 代码
  • D - .. (Double Dots)
    • 题意
    • 题解
    • 代码
  • E - ∙ (Bullet)
    • 题意
    • 题解
    • 代码

前三题比较水,直接上代码

A - ∴ (Therefore)

代码

#include 
using namespace std;

int main() {
    int n; scanf("%d", &n);
    n = n % 10;
    if (n == 3) printf("bon");
    else if (n == 0 || n == 1 || n == 6 || n == 8) printf("pon");
    else printf("hon");



    return 0;
}

B - … (Triple Dots)

代码

#include 
using namespace std;
typedef long long ll;
const int MAX = 1e3 + 10;

int N;
char s[MAX], t[MAX];

int main() {

    scanf("%d%s", &N, s + 1);
    int len = strlen(s + 1);
    if (len <= N) printf("%s\n", s + 1);
    else {
        strncpy(t + 1, s + 1, N);
        printf("%s%s\n", t + 1, "...");
    }



    return 0;
}

C - : (Colon)

代码

#include 
using namespace std;
typedef long long ll;
const int MAX = 1e3 + 10;
const double PI = acos(-1);

double A, B;
int H, M;

int main() {

    scanf("%lf%lf%d%d", &A, &B, &H, &M);
    double totM = H * 60 + M;
    double d1 = totM / 2;
    double d2 = M * 6;
    double d = abs(d1 - d2);
    d = min(d, 360 - d);
    double coss = cos(d / 180 * PI);
    printf("%.16lf\n", sqrt(A * A + B * B - 2 * A * B * coss));


    return 0;
}

D - … (Double Dots)

题意

N N N个点 M M M条边的图,让你在每个点指明一个方向(就是下一个点),使得从每个点出发,沿着点的指定方向走最终能到达点1
如果可以,输出yes,并且给出每个点指明的方向,否则输出no

题解

我们反着考虑,直接从点 1 1 1出发 b f s bfs bfs即可

代码

#include 
using namespace std;
typedef long long ll;
const int MAX = 1e5 + 10;

int N, M;
vector<int> g[MAX];
int ans[MAX], vis[MAX];
queue<int> q;

bool bfs() {
    q.push(1); vis[1] = 1;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (auto &v: g[u])
            if (!vis[v]) {
                ans[v] = u;
                q.push(v); vis[v] = 1;
            }
    }
    for (int i = 1; i <= N; i++)
        if (!vis[i]) return false;
    return true;
}

int main() {
    scanf("%d%d", &N, &M);
    for (int i = 1; i <= M; i++) {
        int u, v; scanf("%d%d", &u, &v);
        g[u].push_back(v), g[v].push_back(u);
    }
    if (bfs()) {
        printf("Yes\n");
        for (int i = 2; i <= N; i++)
            printf("%d\n", ans[i]);
    }
    else printf("No\n");



    return 0;
}

E - ∙ (Bullet)

题意

N N N个点,每个点给出 A i , B i A_i,B_i Ai,Bi
在一个集合中,不能存在满足 A i B j + A j B i = 0 A_iB_j+A_jB_i=0 AiBj+AjBi=0的点对
现在问能选出多少这样的集合

题解

等式转换一下得到, A i B i = − B j A j \frac{A_i}{B_i}=-\frac{B_j}{A_j} BiAi=AjBj
所以可能有很多点 A i B i \frac{A_i}{B_i} BiAi相等,把他们染成相同的颜色
然后不能和他们同时出现的颜色就是 − B j A j -\frac{B_j}{A_j} AjBj,找出他们即可

但是注意,这里等式转换的前提是 A i ≠ 0 , B i ≠ 0 A_i\not=0,B_i\not=0 Ai=0,Bi=0
所以有四种情况:
A i = 0 , B i = 0 A_i=0,B_i=0 Ai=0,Bi=0
A i ≠ 0 , B i = 0 A_i\not=0,B_i=0 Ai=0,Bi=0
A i = 0 , B i ≠ 0 A_i=0,B_i\not=0 Ai=0,Bi=0
A i ≠ 0 , B i ≠ 0 A_i\not=0,B_i\not=0 Ai=0,Bi=0
其中,
①和其他三种都不能在一个集合
②和③不能在一个集合
④中某些点不能在一个集合
那么我们直接染色找即可
还有一个问题
就是 A i B i \frac{A_i}{B_i} BiAi是一个小数,如果我们用 m a p map map来存有可能精度不够(我比赛的时候就是精度炸了)
所以将 A i B i \frac{A_i}{B_i} BiAi转化为分数 a b c a\frac{b}{c} acb的三元组 ( a , b , c ) (a, b, c) (a,b,c)来记录,还要考虑一下符号,所以用两个 m a p map map

最后我们都找到了后,要考虑计算答案
对于一种颜色 c o l o r color color来说,假如它有 s i z siz siz个点
每个点选和不选两种情况,总的就是 2 s i z 2^{siz} 2siz种情况,再减去全都不选的情况,所以最终这个颜色的选法就是 2 s i z − 1 2^{siz}-1 2siz1
然后假如不能和他同时选的另一种颜色是 r h s [ c o l o r ] rhs[color] rhs[color]
那么就是三种情况 选 c o l o r , 选 r h s [ c o l o r ] , 都 不 选 选color,选rhs[color],都不选 color,rhs[color],

这样考虑就行

代码

#include 
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<int, pii> piii;
const int MAX = 2e5 + 10;
const ll mod = 1000000007;

int N;
ll siz[MAX], rhs[MAX], col, vis[MAX];
ll f[MAX], num1, num2;
map<piii, int> mp[2];

piii calc(ll x, ll y) {
    x = abs(x), y = abs(y);
    ll gcd = __gcd(x % y, y);
    return piii{x / y, {x % y / gcd, y / gcd}};
}

int main() {
#ifdef ACM_LOCAL
    freopen("input.in", "r", stdin);
    freopen("output.out", "w", stdout);
#endif
    scanf("%d", &N);
    f[0] = 1;
    for (int i = 1; i <= N; i++) f[i] = 1ll * f[i - 1] * 2 % mod;
    for (int i = 0; i <= N; i++) f[i] = (f[i] - 1 + mod) % mod;
    ll ans = 0;
    for (int i = 1; i <= N; i++) {
        ll a, b; scanf("%lld%lld", &a, &b);
        if (a == 0 && b == 0) ans++;//a=0,b=0,只能选和不选
        else if (a == 0) num1++;
        else if (b == 0) num2++;
        else {
            piii now = calc(a, b), pre = calc(b, a);//转化为三元组
            int state = 0;//判断符号
            if (1.0 * a / b > 0) state = 1;
            if (!mp[state].count(now)) {
                mp[state][now] = ++col;
                if (mp[state ^ 1].count(pre))
                    rhs[col] = mp[state ^ 1][pre], rhs[mp[state ^ 1][pre]] = col;
            }
            siz[mp[state][now]]++;
        }
    }
    ll t = (f[num1] + f[num2] + 1) % mod;//a = 0, b != 0 和 a!=0, b = 0
    for (int i = 1; i <= col; i++)
        if (!vis[i]) {
            vis[i] = 1;
            if (rhs[i]) {
                vis[rhs[i]] = 1;
                t = t * ((1ll + (f[siz[i]] + f[siz[rhs[i]]]) % mod) % mod) % mod;
            }
            else t = t * ((1ll + f[siz[i]]) % mod) % mod;
        }
    ans = (ans + t) % mod;
    printf("%lld\n", (ans - 1 + mod) % mod);

    return 0;
}

你可能感兴趣的:(AtCoder)