欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2018年全国多校算法寒假训练营练习比赛(第三场)解题报告

程序员文章站 2022-04-02 21:29:57
...

2018年全国多校算法寒假训练营练习比赛(第三场)

A 不凡的夫夫

题目描述:

夫夫有一天对一个数有多少位数感兴趣,但是他又不想跟凡夫俗子一样,
所以他想知道给一个整数n,求n!的在8进制下的位数是多少位。

输入描述:

第一行是一个整数t(0

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const double PI = acos(-1.0);
const double E = 2.7182818284;

int main(void) {
    int t;
    cin >> t;
    while (t--) {
        int n;
        scanf("%d", &n);
        ll ans = 1;
        if (n > 1) {
            ans = (ll)ceil(0.5*log(2*PI*n)/log(8) + n*log(n)/log(8) - n*log(E)/log(8));
        }
        printf("%lld\n", ans);
    }
    return 0;
} 

B 一个小问题

题目描述

uu遇到了一个小问题,可是他不想答。你能替他解决这个问题吗?
问题:给你k对a和r是否存在一个正整数x使每队a和r都满足:x mod a=r,求最小正解x或无解。

输入描述:

第一行是正整数k(k<=100000)
接下来k行,每行有俩个正整数a,r(100000>a>r>=0)

输出描述:

在每个测试用例输出非负整数m,占一行。
如果有多个可能的值,输出最小的值。
如果没有可能的值,则输出-1。

思路: 中国剩余定理模板

#include <bits/stdc++.h>
using namespace std;
#define ll long long

void exgcd(ll a, ll b, ll &d, ll &x, ll &y) {
    if (!b) {
        d = a;
        x = 1, y = 0;
    } else {
        exgcd(b, a%b, d, y, x);
        y -= (a/b) * x;
    }
}

ll China(int n, ll *m, ll *a) {
    ll M = m[0], A = a[0], d, y, x;
    for (int i = 1; i < n; i++) {
        exgcd(M, m[i], d, x, y);
        if ((a[i] - A) % d) return -1;
        x = (a[i] - A) / d * x % (m[i] / d);
        A += x*M;
        M = M / d * m[i];
        A %= M; 
    } 
    return A > 0? A : A+M;
}

ll m[100101], a[100101];
int main(void) {
    int k;
    while (cin >> k) {
        for (int i = 0; i < k; i++) {
            cin >> m[i] >> a[i];
        }
        printf("%lld\n", China(k, m, a));
    }
    return 0;
} 

D 小牛vs小客

题目描述:

小牛和小客玩石子游戏,他们用n个石子围成一圈,小牛和小客分别从其中取石子,谁先取完谁胜,每次可以从一圈中取一个或者相邻两个,每次都是小牛先取,请输出胜利者的名字(小牛获胜输出XiaoNiu,小客获胜输出XiaoKe)(1 2 3 4 取走 2 13 不算相邻)

输入描述:

输入包括多组测试数据
每组测试数据一个n(1≤n≤1e9)

输出描述:

每组用一行输出胜利者的名字(小牛获胜输出XiaoNiu,小客获胜输出XiaoKe)

思路: 一个圆, 对方取啥你取啥, 对称着取。 手动算出前几个答案找到规律。

代码:

#include <bits/stdc++.h>
using namespace std;

int main(void) {
    int n;
    while (cin >> n) {
        if (n < 3) {
            cout << "XiaoNiu\n";
        } else {
            cout << "XiaoKe\n";
        }
    }
    return 0;
}

E 进击吧!阶乘

题目描述:

给定一个整数N(0≤N≤10000),求取N的阶乘

输入描述:

多个测试数据,每个测试数据输入一个数N

输出描述:

每组用一行输出N的阶乘

代码:

import java.math.BigInteger;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        while(cin.hasNext()) {
            int n = cin.nextInt();
            BigInteger ans = BigInteger.ONE;
            for (int i = 1; i <= n; i ++) {
                ans = ans.multiply(BigInteger.valueOf(i));
            }
            System.out.println(ans);
        }
    }
}

F 小牛再战

题目描述

共有N堆石子,已知每堆中石子的数量,两个人轮流取石子,每次只能选择N堆石子中的一堆取一定数量的石子(最少取一个),取过子之后,还可以将该堆石子中剩余的石子随意选取几个放到其它的任意一堆或几堆上。等哪个人无法取子时就表示此人输掉了游戏。注意:一堆石子没有子之后,就不能再往此处放石子了。

假设每次都是小牛先取石子,并且游戏双方都绝对聪明,现在给你石子的堆数、每堆石子的数量,请判断出小牛能否获胜。

输入描述:

可能有多组测试数据(测试数据组数不超过1000)
每组测试数据的第一行是一个整数,表示N(1<=N<=10)
第二行是N个整数分别表示该堆石子中石子的数量。(每堆石子数目不超过100)
当输入的N为0时,表示输入结束

输出描述:

对于每组测试数据,输出Win表示小牛可以获胜,输出Lose表示小牛必然会败。

思路:

堆数为奇必赢。

堆数为偶数:如果有当n=2时,易得的条件是a1=a2时为lose,否则为win,

当n>=2时:

当其中有偶数个两两相等的堆时,则为lose (2,2,3,3,1,1),我们可以把他们两两看成一组(2,2),(3,3),(1,1)

当堆数剩下5堆时,当前这个人必赢,所以先手取肯定不会让堆数变5,所以他取其中的某一堆时,后手只要继续维持有偶数个两两相等的堆的性质就必赢

所以当n为偶数时,如果一开始就有偶数个两两相等的堆,则先手Lose

#include <bits/stdc++.h>
using namespace std;

int main(void) {
    int n;
    while (cin >> n && n) {
        int ans = 0;
        for (int i = 0; i < n; i++) {
            int tmp; cin >> tmp;
            ans ^= tmp;
        }
        if (n % 2) puts("Win");
        else {
            if (ans) puts("Win");
            else puts("Lose");
        }
    }
    return 0;
}

G 大水题

题目描述:

给出一个数n,求1到n中,有多少个数不是2 5 11 13的倍数。

输入描述:

本题有多组输入
每行一个数n,1<=n<=10^18.

输出描述:

每行输出输出不是2 5 11 13的倍数的数共有多少。

思路:n很大, 不可直接暴力。 直接求出范围中2 5 11 13的倍数个数有多少个然后容斥一下就好了。

#include <bits/stdc++.h>
using namespace std;
#define ll long long 

int main(void) {

    int a[] = {2, 5, 11, 13};
    int b[] = {10, 22, 26, 55, 65, 143};
    int c[] = {110, 130, 286, 715};
    int d[] = {1430};


    ll n;
    while (cin >> n) {
        ll ans = 0;
        for (int i = 0; i < 4; i++) {
            ans += n / a[i];
        }

        for (int i = 0; i < 6; i++) {
            ans -= n / b[i];
        }

        for (int i = 0; i < 4; i++) {
            ans += n / c[i];
        }

        ans -= n / d[0];
        cout << n-ans << '\n';
    }
    return 0;
} 

I 三角形

https://www.nowcoder.com/acm/contest/75/I

题目描述

给你一个三角形的顶点A,B,C的坐标(坐标都为整数),请求出三角形的面积,三角形内的点的个数以及边AB、BC和AC边上的点的个数(不包括顶点ABC)
2018年全国多校算法寒假训练营练习比赛(第三场)解题报告2018年全国多校算法寒假训练营练习比赛(第三场)解题报告

输入描述:

多组输入
每组输入三行,每行两个整数
第一行顶点A的坐标Xa,Ya.
第二行顶点B的坐标Xb,Yb.
第三行顶点C的坐标Xc,Yc.
0<=X,Y<=1,000,000
输入-1结束输入

输出描述:

每组输出一行,输出一个实数(保留一位小数),四个整数,分别代表三角形面积,三角形内的点的个数以及边AB、BC和AC边上的点的个数,每个数用空格隔开。

#include <bits/stdc++.h>
using namespace std;
#define ll long long

struct Node {
    ll x, y;
}a[110];

ll gcd(ll a, ll b) {
    return b ? gcd(b, a%b) : a;
}

double area() {
    return fabs(0.5*((a[1].x - a[0].x)*(a[2].y - a[0].y) - (a[2].x - a[0].x)*(a[1].y - a[0].y)));
}

ll solve(Node a, Node b) {
    ll x = abs(a.x - b.x);
    ll y = abs(a.y - b.y);
    return gcd(x, y);
}

int main(void) {
    while (cin >> a[0].x && a[0].x != -1) {
        cin >> a[0].y;
        cin >> a[1].x >> a[1].y;
        cin >> a[2].x >> a[2].y;

        ll ans1 = solve(a[0], a[1]) - 1;
        ll ans2 = solve(a[1], a[2]) - 1;
        ll ans3 = solve(a[0], a[2]) - 1;
        double ans = area();
        ll k = ans - 0.5 - (ans1+ans2+ans3) / 2;
        printf("%.1f %lld %lld %lld %lld\n", ans, k, ans1, ans2, ans3);
    }
}


                                    ——END