题目如下
问题描述
勤奋的Farmer John想要建造一个由四面围成的栅栏来关住那些奶牛。他现在有一块长度为N(4 <= N <=100000)的长木板,他需要把这块长木板切成边长均为正整数的四块,使得他能建造一个栅栏。请问他有多少种不同的切割方式能使切割出来的木板围成一个四面的栅栏。
注意:
1. 四边形即可,不一定是矩形。
2. 栅栏围成的面积必须大于0且木板必须用完
3. 结果可以用64位整数存储, 只要大木板的切割点不同就当成是不同的方案
输入格式
仅一行,整数N
输出格式
仅一行,Farmer John能将木板分割开来并能围成四边形的方案数。
样例输入
6
样例输出
6
提示
样例解释:
Farmer John有10中方法将木板分成四块:(1, 1, 1,3); (1, 1, 2, 2); (1, 1, 3, 1); (1, 2, 1, 2); (1, 2, 2, 1); (1, 3,1, 1); (2, 1, 1, 2); (2, 1, 2, 1); (2, 2, 1, 1);(3, 1, 1, 1).
其中有四种情况是不能围成一个四边形的:(1, 1, 1, 3), (1, 1, 3, 1), (1, 3, 1, 1), (3,1, 1, 1)
分析
构成四边形的条件:
任意一边长度 < 周长/2
证明:设四边为a,b,c,d。
因为有a < b+c+d,所以2*a < a+b+c+d = 周长,所以a < 周长/2。
任意一边长度 < 周长/2
证明:设四边为a,b,c,d。
因为有a < b+c+d,所以2*a < a+b+c+d = 周长,所以a < 周长/2。
*f[i][j]:i条边,总长为j的方案数
求=f[4][n];
for(int i=1;i<=4;i++)
for(int j=1;j<=n;j++)
int k=min(j,Len);
f[i][j]=f[i-1][j-k](1<=k<min(j,n/2))=sum[i-1][j-1]-sum[i-1][max(j-k-1,0)];
sum[i][j]=sum[i][j-1]+f[i][j];
}
代码如下
#include<stdio.h> #include<bits/stdc++.h> #define res register long long using namespace std; #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #pragma GCC optimize("inline") #pragma GCC optimize("-fgcse") #pragma GCC optimize("-fgcse-lm") #pragma GCC optimize("-fwhole-program") #pragma GCC optimize("-freorder-blocks") #pragma GCC optimize("-fschedule-insns") #pragma GCC optimize("inline-functions") #pragma GCC optimize("-ftree-tail-merge") long long f[5][100005]; long long sum[5][100005]; int n,Len; inline int read() { int s=0; char c=getchar(); while (c<'0' || c>'9') c=getchar(); while (c>='0' && c<='9') s=s*10+c-'0',c=getchar(); return s; } int main() { ios::sync_with_stdio(false); cout.tie(NULL); n=read(); Len=(n+1)/2-1; for(res i=1;i<=Len;i++)f[1][i]=1; for(res i=1;i<=n;i++)sum[1][i]=sum[1][i-1]+f[1][i]; for(int i=2; i<=4; i++) for(int j=1; j<=n; j++) { int k=min(j,Len); f[i][j]=sum[i-1][j-1]-sum[i-1][max(j-k-1,0)]; sum[i][j]=sum[i][j-1]+f[i][j]; } cout<<f[4][n]; }