题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4486
题目意思:
给一个长度len,求把len分成三段凑成三角形的个数,如果是等腰三角形记1种,非等腰的记两种。
解题思路:
三角形计数。比赛的时候傻逼的用o(n^2)的暴力方法打表,虽然过了,不能更弱。。。-_- -_- ! ==思路不行,马上转化,不要陷入死胡同。不受不正确思路影响。之前应该见过这样的计数的。。。。
分几种情况考虑:记三边为a<=b<=c
1、当n%3==0时,可能为等边三角形 +1
2、当a=b<c时,由a+b>c得2a>c 即2a>n-2a 得a>n/4 又由a<c得 a<n-2a 得a<n/3 综合得 n/4<a<n/3 对于每一个a总能构造一种。
3、当a<b=c时,由c>a得c>n-2c 即c>n/3 又b+c<n得 c<n/2 综合得 n/3<c<n/2 对于每一个c总能唯一构造一种。
4、当a<b<c时,枚举a(1~n/3) , 由a<b<n-a-b 得b<(n-a)/2 由a+b>c a+b>n-a-b 得b>(n-2a)/2 综合得 max(a,(n-2a)/2)<b<(n-a)/2 a、b确定了三角形也就唯一确定了。
代码:
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
/*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/
int n;
int up,dow;
int uup(int x,int div) //返回<x/div的上届整数
{
if(x%div==0)
return x/div-1;
return x/div;
}
int ddow(int x,int div)//返回>x/div的下届整数
{
return x/div+1;
}
int main()
{
int t,d;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&d,&n);
int ans=0;
if(n%3==0)
ans+=1; //当a=b=c时的情况
//printf("1:%d\n",ans);
up=uup(n,3);
dow=ddow(n,4);
if(up>=dow)
ans+=(up-dow+1); //当a=b<c时的情况
// printf("2:%d\n",ans);
up=uup(n,2);
dow=ddow(n,3);
if(up>=dow)
ans+=(up-dow+1); //当a<b=c时的情况
// printf("3:%d\n",ans);
for(int a=1;a<n/3;a++) //当a<b<c时的情况
{
dow=ddow(a,1);
int tmp=ddow(n-2*a,2);
up=uup(n-a,2);
dow=max(dow,tmp);
if(up>=dow)
ans+=(2*(up-dow+1));
}
printf("%d %d\n",d,ans);
}
return 0;
}