题目链接: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);
    }
}