2010-1067

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

== Contest 1 by ACFun - Bug Races ==


'''题目大意'''[[BR]]
有两只蚂蚁和一个三维长方体,两只蚂蚁要从此长方体的一个角走到其对角,第一只蚂蚁要沿着长方体表面最短路走,另一只要走形内最短路(即对角连线),要求第一只蚂蚁所走路程长度为整数,求给定长方体最长边长度的条件下,两只蚂蚁所有符合条件路线长度的平均值,用既约分数表示。

'''解法'''[[BR]]
首先可以得知一对符合条件的路线一定与一个长方体一一对应,因此假设长方体三边长分别为a, b, c且a <= b <= c,则有(a + b) * (a + b) + c * c = t * t,其中t为正整数,c等于读入的n值。整理以上的式子,可以得到c * c = (t + a + b) * (t - a - b)。则可以对c * c做因式分解,得出每一种a + b的取值可能性,之后利用平方和公式,得出答案。需要注意的是,答案会超过长整型(64位整数)的范围,可以使用实现了部分功能的大数模板或者java的BigInteger实现。
另外,标程的做法是提前预处理,这样的程序大致需要4秒左右,而直接运算需要870毫秒。

'''未做预处理的java代码'''
{{{
#!java
import java.util.*;
import java.math.*;
import java.io.*;

class BugRaces{
    static int MAXN = 1000000;
    static int[] minp = new int[1000001], plist = new int[1000001], p0 = new int[5000], p1 = new int[5000];
    static long tmp, tmpa, tmpb, N, low, high;
    static BigInteger[] A = new BigInteger[2];
    static BigInteger B, H, L, g;
    static int prime() {
        int num = 0;
        for(int i = 0;i <= MAXN;i++) minp[i] = 0;
        for (int i = 2; i <= MAXN; i++) {
            if (minp[i] == 0){
                plist[num++] = i;
                minp[i] = i;
            }
            for (int j = 0; j < num && i * plist[j] <= MAXN; j++) {
                minp[i * plist[j]] = plist[j];
                if (i % plist[j] == 0) break;
            }
        }
        return num;
    }
    static int factorize(int n) {
        int num = 0;
        while (n != 1) {
            if(num == 0 || minp[n] != p0[num - 1]){
                p0[num] = minp[n];
                p1[num++] = 2;
            }else{
                p1[num - 1] += 2;
            }
            n /= minp[n];
        }
        return num;
    }
    static void calc(int dep, long val){
        if(val <= N){
            if(dep > 0){
                calc(dep - 1, val);
                for(int i = 0;i < p1[dep - 1];i++){
                    val *= p0[dep - 1];
                    if(val > N) return;
                    calc(dep - 1, val);
                }
            }else{
                tmp = N * N / val;
                if((tmp & 1) != (val & 1)) return;
                tmpa = (tmp + val) >> 1;
                tmpb = (tmp - val) >> 1;
                if(tmpb <= (N << 1)){
                    low = Math.max(1, tmpb - N) - 1;
                    high = Math.min(N, tmpb >> 1);
                    if(low < high){
                        H = BigInteger.valueOf(high); L = BigInteger.valueOf(low);
                        B = B.add(H.subtract(L));
                        A[0] = A[0].add(BigInteger.valueOf(tmpa).multiply(BigInteger.valueOf(tmpa)).multiply(H.subtract(L)));
                        A[1] = A[1].add(BigInteger.valueOf(N).multiply(BigInteger.valueOf(N)).multiply(H.subtract(L)));
                        A[1] = A[1].add((H.multiply(H.add(BigInteger.ONE)).shiftRight(1)).multiply(H.add(H).add(BigInteger.ONE)).divide(BigInteger.valueOf(3)));
                        A[1] = A[1].subtract((L.multiply(L.add(BigInteger.ONE)).shiftRight(1)).multiply(L.add(L).add(BigInteger.ONE)).divide(BigInteger.valueOf(3)));
                        low = tmpb - low - 1;
                        high = tmpb - high - 1;
                        H = BigInteger.valueOf(high); L = BigInteger.valueOf(low);
                        A[1] = A[1].subtract((H.multiply(H.add(BigInteger.ONE)).shiftRight(1)).multiply(H.add(H).add(BigInteger.ONE)).divide(BigInteger.valueOf(3)));
                        A[1] = A[1].add((L.multiply(L.add(BigInteger.ONE)).shiftRight(1)).multiply(L.add(L).add(BigInteger.ONE)).divide(BigInteger.valueOf(3)));
                    }
                }
            }
        }
    }
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        prime();
        while(sc.hasNextInt()){
            N = sc.nextInt();
            int dep = factorize((int)N);
            A[0] = A[1] = B = BigInteger.ZERO;
            calc(dep, 1);
            if(B.equals(BigInteger.ZERO))
                System.out.println("NaN NaN");
            else for(int i = 0;i < 2;i++){
                g = A[i].gcd(B);
                System.out.print(A[i].divide(g) + "/" + B.divide(g));
                if(i == 0) System.out.print(" "); else System.out.println();
            }
        }
    }
}
}}}

'''watashi的标准程序'''
{{{
#!cpp
#include <cstdio>
#include <vector>
#include <utility>
#include <cassert>
#include <algorithm>

using namespace std;

const int LIMIT = 1000001;
const int RLIMIT = 1600;

template<typename T>
inline T gcd(T a, T b) {
    return b == 0 ? a : gcd(b, a % b);
}

struct BigInt {
    static const long long MOD = 1000000000000000000LL;
    long long h, l;

    BigInt() : h(0), l(0) {
    }

    void add(long long x) {
        l += x;
        while (l >= MOD) {
            l -= MOD;
            ++h;
        }
    }

    void print(long long x) {
        if (x == 0) {
            printf("NaN");
            return;
        }
        long long g = gcd((h % x) * (MOD % x) + l, x);
        long long hh = h / g;
        long long ll = (h % g) * (MOD / g) + ((h % g) * (MOD % g) + l) / g;
        if (hh > 0) {
            printf("%lld%018lld/%lld", hh, ll, x / g);
        } else {
            printf("%lld/%lld", ll, x / g);
        }
    }
};

// r=first; s=second
// x=r^2-s^2; y=2rs; z=r^2+s^2
// vector<pair<int, int> > pythagoras;
// static BigInt a[LIMIT];
// static BigInt b[LIMIT];
// static long long c[LIMIT];

static struct ABC {
    BigInt a, b;
    long long c;
} abc[LIMIT];


inline long long sum2(long long n) {    // \sum_{i=0}^n{i^2}
    return n * (n + 1) / 2 * (n + n + 1) / 3;
}

inline void gao(long long x, long long y) {
    long long l = max(1LL, x - y);
    long long r = x / 2 + 1;
    if (l < r) {
        abc[y].a.add((x * x + y * y) * (r - l));
        abc[y].b.add(sum2(r - 1) - sum2(l - 1));
        abc[y].b.add(sum2(x - l) - sum2(x - r));
        abc[y].b.add((y * y) * (r - l));
        abc[y].c += r - l;
    }
}

void init() {
    // pythagoras
    for (int r = 1; r < RLIMIT; ++r) {
        for (int s = r % 2 + 1; s < r; s += 2) {
            if (gcd(r, s) == 1) {
                int x = r * r - s * s;
                int y = 2 * r * s;
                if (x > y) {
                    swap(x, y);
                }
                for (long long i = x, j = y; i < LIMIT; i += x, j += y) {
                //  pythagoras.push_back(make_pair(i, j));
                    if (j < LIMIT) {
                        gao(i, j);
                    }
                    gao(j, i);
                }
            }
        }
    }
    // printf("%d\n", pythagoras.size());   // 2388959
}

int main() {
    int n = 0;

    init();
    while (scanf("%d", &n) != EOF) {
        assert(1 <= n && n <= 1000000);
        abc[n].a.print(abc[n].c);
        putchar(' ');
        abc[n].b.print(abc[n].c);
        puts("");
    }

    return 0;
}
}}}

Contest 1 by ACFun - Bug Races

题目大意

有两只蚂蚁和一个三维长方体,两只蚂蚁要从此长方体的一个角走到其对角,第一只蚂蚁要沿着长方体表面最短路走,另一只要走形内最短路(即对角连线),要求第一只蚂蚁所走路程长度为整数,求给定长方体最长边长度的条件下,两只蚂蚁所有符合条件路线长度的平均值,用既约分数表示。

解法

首先可以得知一对符合条件的路线一定与一个长方体一一对应,因此假设长方体三边长分别为a, b, c且a <= b <= c,则有(a + b) * (a + b) + c * c = t * t,其中t为正整数,c等于读入的n值。整理以上的式子,可以得到c * c = (t + a + b) * (t - a - b)。则可以对c * c做因式分解,得出每一种a + b的取值可能性,之后利用平方和公式,得出答案。需要注意的是,答案会超过长整型(64位整数)的范围,可以使用实现了部分功能的大数模板或者java的BigInteger实现。

另外,标程的做法是提前预处理,这样的程序大致需要4秒左右,而直接运算需要870毫秒。

未做预处理的java代码

import java.util.*;
import java.math.*;
import java.io.*;
class BugRaces{
    static int MAXN = 1000000;
    static int[] minp = new int[1000001], plist = new int[1000001], p0 = new int[5000], p1 = new int[5000];
    static long tmp, tmpa, tmpb, N, low, high;
    static BigInteger[] A = new BigInteger[2];
    static BigInteger B, H, L, g;
    static int prime() {
        int num = 0;
        for(int i = 0;i <= MAXN;i++) minp[i] = 0;
        for (int i = 2; i <= MAXN; i++) {
            if (minp[i] == 0){
                plist[num++] = i;
                minp[i] = i;
            }
            for (int j = 0; j < num && i * plist[j] <= MAXN; j++) {
                minp[i * plist[j]] = plist[j];
                if (i % plist[j] == 0) break;
            }
        }
        return num;
    }
    static int factorize(int n) {
        int num = 0;
        while (n != 1) {
            if(num == 0 || minp[n] != p0[num - 1]){
                p0[num] = minp[n];
                p1[num++] = 2;
            }else{
                p1[num - 1] += 2;
            }
            n /= minp[n];
        }
        return num;
    }
    static void calc(int dep, long val){
        if(val <= N){
            if(dep > 0){
                calc(dep - 1, val);
                for(int i = 0;i < p1[dep - 1];i++){
                    val *= p0[dep - 1];
                    if(val > N) return;
                    calc(dep - 1, val);
                }
            }else{
                tmp = N * N / val;
                if((tmp & 1) != (val & 1)) return;
                tmpa = (tmp + val) >> 1;
                tmpb = (tmp - val) >> 1;
                if(tmpb <= (N << 1)){
                    low = Math.max(1, tmpb - N) - 1;
                    high = Math.min(N, tmpb >> 1);
                    if(low < high){
                        H = BigInteger.valueOf(high); L = BigInteger.valueOf(low);
                        B = B.add(H.subtract(L));
                        A[0] = A[0].add(BigInteger.valueOf(tmpa).multiply(BigInteger.valueOf(tmpa)).multiply(H.subtract(L)));
                        A[1] = A[1].add(BigInteger.valueOf(N).multiply(BigInteger.valueOf(N)).multiply(H.subtract(L)));
                        A[1] = A[1].add((H.multiply(H.add(BigInteger.ONE)).shiftRight(1)).multiply(H.add(H).add(BigInteger.ONE)).divide(BigInteger.valueOf(3)));
                        A[1] = A[1].subtract((L.multiply(L.add(BigInteger.ONE)).shiftRight(1)).multiply(L.add(L).add(BigInteger.ONE)).divide(BigInteger.valueOf(3)));
                        low = tmpb - low - 1;
                        high = tmpb - high - 1;
                        H = BigInteger.valueOf(high); L = BigInteger.valueOf(low);
                        A[1] = A[1].subtract((H.multiply(H.add(BigInteger.ONE)).shiftRight(1)).multiply(H.add(H).add(BigInteger.ONE)).divide(BigInteger.valueOf(3)));
                        A[1] = A[1].add((L.multiply(L.add(BigInteger.ONE)).shiftRight(1)).multiply(L.add(L).add(BigInteger.ONE)).divide(BigInteger.valueOf(3)));
                    }
                }
            }
        }
    }
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        prime();
        while(sc.hasNextInt()){
            N = sc.nextInt();
            int dep = factorize((int)N);
            A[0] = A[1] = B = BigInteger.ZERO;
            calc(dep, 1);
            if(B.equals(BigInteger.ZERO))
                System.out.println("NaN NaN");
            else for(int i = 0;i < 2;i++){
                g = A[i].gcd(B);
                System.out.print(A[i].divide(g) + "/" + B.divide(g));
                if(i == 0) System.out.print(" "); else System.out.println();
            }
        }
    }
}

watashi的标准程序

#include <cstdio>
#include <vector>
#include <utility>
#include <cassert>
#include <algorithm>
using namespace std;
const int LIMIT = 1000001;
const int RLIMIT = 1600;
template<typename T>
inline T gcd(T a, T b) {
    return b == 0 ? a : gcd(b, a % b);
}
struct BigInt {
    static const long long MOD = 1000000000000000000LL;
    long long h, l;
    BigInt() : h(0), l(0) {
    }
    void add(long long x) {
        l += x;
        while (l >= MOD) {
            l -= MOD;
            ++h;
        }
    }
    void print(long long x) {
        if (x == 0) {
            printf("NaN");
            return;
        }
        long long g = gcd((h % x) * (MOD % x) + l, x);
        long long hh = h / g;
        long long ll = (h % g) * (MOD / g) + ((h % g) * (MOD % g) + l) / g;
        if (hh > 0) {
            printf("%lld%018lld/%lld", hh, ll, x / g);
        } else {
            printf("%lld/%lld", ll, x / g);
        }
    }
};
// r=first; s=second
// x=r^2-s^2; y=2rs; z=r^2+s^2
// vector<pair<int, int> > pythagoras;
// static BigInt a[LIMIT];
// static BigInt b[LIMIT];
// static long long c[LIMIT];
static struct ABC {
    BigInt a, b;
    long long c;
} abc[LIMIT];
inline long long sum2(long long n) {    // \sum_{i=0}^n{i^2}
    return n * (n + 1) / 2 * (n + n + 1) / 3;
}
inline void gao(long long x, long long y) {
    long long l = max(1LL, x - y);
    long long r = x / 2 + 1;
    if (l < r) {
        abc[y].a.add((x * x + y * y) * (r - l));
        abc[y].b.add(sum2(r - 1) - sum2(l - 1));
        abc[y].b.add(sum2(x - l) - sum2(x - r));
        abc[y].b.add((y * y) * (r - l));
        abc[y].c += r - l;
    }
}
void init() {
    // pythagoras
    for (int r = 1; r < RLIMIT; ++r) {
        for (int s = r % 2 + 1; s < r; s += 2) {
            if (gcd(r, s) == 1) {
                int x = r * r - s * s;
                int y = 2 * r * s;
                if (x > y) {
                    swap(x, y);
                }
                for (long long i = x, j = y; i < LIMIT; i += x, j += y) {
                //  pythagoras.push_back(make_pair(i, j));
                    if (j < LIMIT) {
                        gao(i, j);
                    }
                    gao(j, i);
                }
            }
        }
    }
    // printf("%d\n", pythagoras.size());   // 2388959
}
int main() {
    int n = 0;
    init();
    while (scanf("%d", &n) != EOF) {
        assert(1 <= n && n <= 1000000);
        abc[n].a.print(abc[n].c);
        putchar(' ');
        abc[n].b.print(abc[n].c);
        puts("");
    }
    return 0;
}