虽然不难,可以轻松使用小学奥数的想法解决,但是我已经小学毕业了,如何更无脑解决这个问题呢?
发现答案无论怎么样都是个多项式,所以考虑一下小范围暴力,然后拉格朗日插值求出远处的答案。
小范围的暴力很好写,直接 O(n^6) 枚举三角形三个点,再用叉积公式计算面积就好了!
怎么插值呢,毕竟是二维的,你可以一维一维的做,先算出来 ans[1,2,3,...,20][m],再用这个数组叉出来 ans[n][m]。
时间复杂度居然也是 O(1)。
#include<bits/stdc++.h>
#define int long long
#define mod 1000000007
using namespace std;
int quickpow(int a,int b){
int ret=1;
while(b){
if(b&1) ret=ret*a%mod;
a=a*a%mod;
b>>=1;
}return ret;
}
int inv[114514];
void init(int n=114513){
for(int i=1;i<=n;i++) inv[i]=quickpow(i,mod-2);
}
int lag(vector<pair<int,int> > vec,int x){
for(auto u:vec){
if(u.first==x) return u.second;
}
int ret=0;
for(int i=0;i<vec.size();i++){
int s=1;
for(int j=0;j<vec.size();j++){
if(i==j) continue;
int d=vec[i].first-vec[j].first;
if(d>0) s=s*(x-vec[j].first)%mod*inv[d]%mod;
else s=s*(x-vec[j].first)%mod*inv[-d]%mod,s=mod-s;
}s%=mod;
ret+=s*vec[i].second%mod;
}ret%=mod;
return ret;
}
int ans[21][21];
int Ans[21];
signed main(){
init();
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int n,m;
cin>>n>>m;
for(int i=1;i<=20;i++){
for(int j=1;j<=20;j++){
for(int x=1;x<=20;x++){
for(int y=1;y<=20;y++){
for(int a=1;a<=20;a++){
for(int b=1;b<=20;b++){
int lf=0;
lf+=a==x;
lf+=a==i;
lf+=x==i;
lf+=b==y;
lf+=b==j;
lf+=y==j;
if(!lf) continue;
int v1x=i-x,v1y=j-y;
int v2x=a-x,v2y=b-y;
int S=abs(v1x*v2y-v1y*v2x);
if(S==2){
ans[max({i,x,a})][max({j,y,b})]++;
}
}
}
}
}
}
}
for(int i=1;i<=20;i++){
for(int j=1;j<=20;j++){
ans[i][j]=ans[i][j]+ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1];
}
}
for(int i=1;i<=20;i++){
vector<pair<int,int> > vec;
for(int j=3;j<=10;j++){
vec.push_back({j,ans[i][j]});
}
Ans[i]=lag(vec,m);
}
vector<pair<int,int> > vec;
for(int i=3;i<=10;i++) vec.push_back({i,Ans[i]});
cout<<lag(vec,n)*quickpow(6,mod-2)%mod;
}

京公网安备 11010502036488号