前缀和优化例题1(【Usaco Oct08 Gold】建造栅栏(Building A Fence))

探讨了如何从一块固定长度的长木板中切割出四块边长为正整数的木板,以构建一个四边形栅栏的问题。通过动态规划的方法,计算出了所有可能的切割方案数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目如下
问题描述

勤奋的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


*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];
    }

 

 

转载于:https://www.cnblogs.com/CXYscxy/p/11027663.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值