题目链接:https://vjudge.net/problem/%E8%AE%A1%E8%92%9C%E5%AE%A2-A2144
题目大意:
求n行三角形中等边三角形的个数,图二的三角形也算,n<=1e9
解题思路:
n范围这么大,一看就是个找规律题,那么先来打个表看看。
打表(暴力)代码:
#include<bits/stdc++.h>
using namespace std;
struct node{
double x, y;
}a[6000];
int n, cnt;
double dis(int i, int j)
{
return sqrt( (a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y) );
}
bool check(int i, int j, int k)
{
double a = dis(i, j);
double b = dis(i, k);
double c = dis(j, k);
if(fabs(a-b)<=0.0000001&&fabs(a-c)<=0.0000001&&fabs(b-c)<=0.0000001) return true;
return false;
}
int main()
{
while(cin >> n) {
cnt = 0;
double posx = 0;
double posy = 0; //从(0,0)开始
for(int i = 0; i <= n; i++) {
posx = 0.5*i;
for(int j = 0; j <= n-i; j++) {
// cout << posx <<" "<<posy<<endl;
a[cnt].x = posx;
a[cnt++].y = posy;
posx += 1.0;
}
posy += sqrt(3) / 2.0;
}
int ans = 0;
for(int i = 0; i < cnt ; i++) {
for(int j = i+1; j < cnt; j++) {
for(int k = j+1; k < cnt; k++) {
if(check(i, j, k)) ans++;
}
}
}
printf("%d: %d\n",n,ans);
}
}
打表后的结果:
1,5,15,35,70,126,210...
没感觉?
做差
4,10,20,35,56,84...
继续做差
6,10,15,21,28...
再做差
4,5,6,7... 这是一个等差数列了,那么再做一次差就是常数列了。
每一次做差都是在对离散函数的相邻两点求斜率,这很像是在求导!
我们不妨把这种过程看作是在求导,那么做差4次后(4阶导数)是常数。
因此我们设函数
代入打表的结果,解得a=1/24 , b=6/24, c=11/24, d=6/24, e=0。
提出1/24出来,
逆元+O(1)搞定。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
ll q_pow(ll a, ll b, ll m){
ll ans = 1;
while(b > 0){
if(b & 1){
ans = ans * a % m;
}
a = a * a % m;
b >>= 1;
}
return ans;
}
ll inv(ll a, ll p)
{
return q_pow(a, p-2, p);
}
int main()
{
int t;
scanf("%d",&t);
while(t--) {
ll n;
scanf("%lld",&n);
ll ans = (((((n*n)%mod)*n)%mod)*n)%mod + 6*(((n*n)%mod)*n)%mod + (11*(n*n%mod))%mod + 6*n%mod;
ans %= mod;
ans = (ans* inv(24, mod)) % mod;
printf("%lld\n",ans);
}
}
京公网安备 11010502036488号