【CF-gym101964:B】Broken Watch(找规律+推导+自然溢出/java大数)

题目地址:https://codeforces.com/gym/101964/problem/B

题目:


给出表盘的时针、分针、秒针的长度A, B, C和表盘刻度数N,求时针、分针、秒针任意指向一个刻度,针点构成的包含圆心的三角形数目(包括圆心在三角形边上的情况)

解题思路:


为了简化问题,我们先考虑A=B=C的情况,其他情况就是在此基础上进行多重排列了。

(1)N为偶数

整个圆上的点都是对称的,固定一个点A,枚举另一个点B,可以确定C的可取点在A和B关于原点的对称点A'B'之间,包括边界上的点。为了避免重复,只枚举上半部分的A, 最终*2就是答案。

例如:N=10

枚举方法:令m=N/2-1

A在A,B在B/C/D/E,可以确定的三角形数为:2+3+4+5

A在B,B在C/D/E,可以确定的三角形数为:2+3+4

扫描二维码关注公众号,回复: 8807265 查看本文章

A在C,B在D/E,可以确定的三角形数为:2+3

A在D,B在E,可以确定的三角形数为:2

通过等差数列的求和公式和1^2+2^2+...+n^2=n(n+1)(2n+1)/6,可以推出公式:

ans=\frac{m*(m+1)*(m+5)}{3}

(2)N为基数

和N为偶数的枚举思路基本一致,但是当N为基数时,除了在x轴上的一个点之外,其他的点是上下对称的,故x轴上点需要单独枚举,其他的只需要枚举上半部分的点。

例如N=7:

枚举方法:令m=N/2

A在A点,B在B/C/D点,可以确定的三角形数为:1+2+3

A在B点,B在C/D点,可以确定的三角形数为:1+2

A在C点,B在D点,可以确定的三角形数为:1

通过等差数列的求和公式和1^2+2^2+...+n^2=n(n+1)(2n+1)/6,可以推出公式:

ans=\frac{m*(m+1)*(2m+1)}{6}

当三条边是ABC类型的,ans=ans*6;当三条边是AAB类型的,ans=ans*3

注意:答案要对2^64取模,相当于自然溢出,可以用unsigned long long ,但是在计算ans的分子是自然溢出之后的值会小于分母,用逆元的话又有些麻烦,既然ans为正数,可以先用分子一点点把分母消掉再乘起来。(或者直接用java写)

ac代码:


c++

#include <iostream>
#include <math.h>
using namespace std;
typedef unsigned long long ll;
ll A, B, C, N;
int judge()
{
    if(A == B && B == C) return 3;
    else if(A != B && B != C) return 1;
    else return 2;
}
ll gcd(ll a, ll b)
{
    return b == 0 ? a : gcd(b, a%b);
}
int main()
{
    cin >> A >> B >> C >> N;
    if(N == 2) printf("0");
    else
    {
        int e = judge();
        ll m = N / 2, ans;
        if(N%2 == 0)
        {
            m--;
            ll a = m, b = m+1, c = m+5;
            if(a%3 == 0) a /= 3;
            else if(b%3 == 0)  b /= 3;
            else if(c%3 == 0) c /= 3;
            ans = a * b * c;
        }
        else
        {
            ll a = m, b = m+1, c = 2*m+1, mul = 1;
            ll ga = gcd(a, 6), gb = gcd(b, 6), gc = gcd(c, 6);
            if(ga != 1 && mul != 6) a /= ga, mul *= ga;
            if(gb != 1 && mul != 6) b /= gb, mul *= gb;
            if(gc != 1 && mul != 6) c /= gc, mul *= gc;
            ans = a * b * c;
        }
        if(e == 1)
            ans = ans * 6;
        else if(e == 2)
            ans = ans * 3;
        cout << ans;
    }
    return 0;
}

JAVA:

import java.math.BigInteger;
import java.util.*;
public class Main 
{
	public static void main(String[] args)
	{
		Scanner input = new Scanner(System.in);
		BigInteger A = input.nextBigInteger();
		BigInteger B = input.nextBigInteger();
		BigInteger C = input.nextBigInteger();
		BigInteger N = input.nextBigInteger();
		BigInteger x1 = new BigInteger("1");
		BigInteger x2 = new BigInteger("2");
		BigInteger x5 = new BigInteger("5");
		BigInteger x3 = new BigInteger("3");
		BigInteger x6 = new BigInteger("6");
		BigInteger x0 = new BigInteger("0");
		BigInteger MOD = x2.pow(64);
		BigInteger ans;
		int e = 0;
		if(A.equals( B) && B.equals(C))  e = 3;
		else if(!A.equals(B) && !B.equals(C) && !A.equals(C)) e = 1;
		else e = 2;
		BigInteger m = N.divide(x2);
		if((N.mod(x2)).equals(x0))
		{
			m = m.subtract(x1);
			BigInteger a = m; 
			BigInteger b = m.add(x1);
			BigInteger c = m.add(x5);
			ans =  a.multiply(b).multiply(c).divide(x3);
		}
		else
		{
			BigInteger a = m;
			BigInteger b = m.add(x1); 
			BigInteger c = m.multiply(x2).add(x1);
			ans = a.multiply(b).multiply(c).divide(x6);
		}
		if(e == 2) ans = ans.multiply(x3);
		else if(e == 1) ans = ans.multiply(x6);
		System.out.print(ans.mod(MOD));
	}
}
发布了299 篇原创文章 · 获赞 81 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/Cassie_zkq/article/details/101202727