题目链接: http://www.icpc.moe/onlinejudge/showProblem.do?problemId=5630
一道数学题。可惜我从小数学就不好...
首先是公式推导,参考博客:http://blog.youkuaiyun.com/bigbigship/article/details/49123643 感谢!
具体是这样:
设最长的边为
n
,最短的边为
x
,次短的边为
y
,
ΣL2=∑nx=1∑ny=xn2+(x+y)2
ΣL2=n∗(n+1)/2∗n2+∑nx=1∑ny=xx2+y2+2∗x∗y
设
Sum1=∑nx=1∑ny=x2∗x∗y
Sum1=∑nx=12∗x∑ny=xy
Sum1=∑nx=12∗x∗(x+n)∗(n−x+1)/2
Sum1=∑nx=1−x3+x2+(n2+n)∗x
设
Sum2=∑nx=1∑ny=xx2+y2
由于
x,y
的取值范围都为
[1,n]
,并且每个数的平方都恰好出现了
n+1
次
因此
Sum2=∑nx=1x2∗(n+1)
ΣL2=Sum1+Sum2+n*(n+1)/2=∑nx=1(−x3+(n+2)∗x2+(n2+n)∗x) +n*(n+1)/2
补充三个求和公式:
∑nx=1x=n∗(n+1)/2
∑nx=1x2=n∗(n+1)∗(2∗n+1)/6
∑nx=1x3=[n∗(n+1)/2]2
另外我这个小白从这一题学会了利用费马小定理求逆元,参考博客:https://www.huangwenchao.com.cn/2014/05/mod-div.html 感谢!
带模的除法可以转换成带模乘法,带模除法是不满足同余定理的。
用费马小定理求逆元的意思是,带模的除法:求 a / b = x (mod M)
只要 M 是一个素数,而且 b 不是 M 的倍数,就可以用一个逆元整数 b’,通过 a / b = a * b' (mod M),来以乘换除。
费马小定理说,对于素数 M 任意不是 M 的倍数的 b,都有:
b ^ (M-1) = 1 (mod M)
于是可以拆成:
b * b ^ (M-2) = 1 (mod M)
于是:
a / b = a / b * (b * b ^ (M-2)) = a * (b ^ (M-2)) (mod M)
也就是说我们要求的逆元就是 b ^ (M-2) (mod M)
这样就只需写一个快速幂来求2,、4、6的逆元即可。
数学好伟大。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
typedef long long ll;
const ll m = 1000000007;
ll qpow(ll a, ll b) {
ll res = 1;
while(b) {
if(b & 1) res = res * a % m;
a = a * a % m;
b >>= 1;
}
return res;
}
int main() {
ll inv2 = qpow(2ll, m - 2);
ll inv4 = qpow(4ll, m - 2);
ll inv6 = qpow(6ll, m - 2);
int T;
scanf("%d", &T);
while(T--) {
ll n;
scanf("%lld", &n);
n %= m;
ll ans = 0;
ans = (n + 1) % m * n % m * inv2 % m * n % m * n % m;
ans = (ans - n * n % m * (n + 1) % m * (n + 1) % m * inv4 % m + m) % m;
ans = (ans + (n + 2) % m * n % m * ((n + 1) % m) % m * ((2 * n + 1) % m) % m * inv6 % m) % m;
ans = (ans + (n * n + n) % m * n % m * (n + 1) % m * inv2 % m) % m;
printf("%lld\n", ans);
}
return 0;
}
本文介绍了ZOJ 3903 Ant问题的解决过程,涉及数学公式推导,包括最长边、最短边和次短边的关系,以及求和公式的应用。同时,作者分享了如何利用费马小定理求解带模逆元,通过将带模除法转化为带模乘法来简化计算。
285

被折叠的 条评论
为什么被折叠?



