184. [USACO Oct08] 搭建篱笆
★★ 输入文件:quad.in
输出文件:quad.out
简单对比
时间限制:1 s 内存限制:128 MB
勤奋的农夫约翰想要修建一个4面的篱笆墙把他的奶牛们围起来。他有一块长为N的木板(4<=N<=2500)于是他想要在三个点把他们切断用以得到4块木板。
只要能构成成四边形篱笆,这4块板子的长度可以是任意正整数。那么为了得到完整的篱笆农夫约翰有多少不同的种方法切这个长木板呢?
注意:
- 对于两种方案而言,只要一方存在一个另一方没有的切割点,那它们就将视为不同的方案。不必担心对称或那个其他复杂的情况的排除。
- 请注意,篱笆所围的面积应当大于0。
- 你将高兴的是,我们保证答案适合有符号的32位整型变量。
分数:250
问题名称:quad
输入格式:
- 第1行:一个单独的整数:N
输入样例(file quad.in):
6
输入说明:这个板子的长度是6。
输出格式:
- 第1行:一个单独的整数表示切割方案数。
输出样例:
6
输出说明:
农夫约翰有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).
但是其中的4种--(1,1,1,3),(1,1,3,1),(1,3,1,1),(3,1,1,1)是不能构成篱笆的。
思路:
方法一:排列组合。
首先,我们可以考虑用f[i]来表示当前用了长度为i时的方案数。。
但是根本行不通qwq。所以因该运用补集的思想来转化一下。当总长度为k的时候,很明显总方案数是C(n-1,3)就是在n-1个点中选出3个点来切;然后考虑不合法的情况即当最长边长度大于总长度的一半。我们可以枚举不合法的最长边长度然后再次运用排列组合的方法来求解,即C(n-1-t,2),其中t是枚举的长度。这里容易忽略一个条件就是枚举出来的那条边可以插在求解出的情况的中间或两边,所以应该减去4*C(n-1-t,2)即可。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
long long n;
int main(){
freopen("quad.in","r",stdin);
freopen("quad.out","w",stdout);
scanf("%lld",&n);
long long ans=(n-)*(n-)*(n-)/;
long long temp=;
long long mod=n%;
for(int i=(n/)+mod;i<=n-;i++)
ans-=(n-i-)*(n-i-)*;
printf("%lld",ans);
return ;
}
方法二:动规
用f[i][j]表示前i块木板长度和为j的方案
构成四边形的条件是三边和大于第四边
也就是任意一条边的长度都是小于边长之和的一半
#include<iostream>
#include<cstdio>
using namespace std;
int n,mx;
int f[][];
int main(){
f[][]=;
scanf("%d",&n);
int mx=(n+)/-;
for(int i=;i<=;i++)
for(int j=;j<=n;j++)
for(int k=;k<=min(mx,j);k++)
f[i][j]+=f[i-][j-k];
printf("%d",f[][n]);
return ;
}