代码参考自:xyz111
题意: 众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:
勇太有一根长度为n的木棍,这个木棍是由n个长度为1的小木棍拼接而成,当然由于时间放置的久了,一些小木棍已经不牢固了,所以勇太想让六花把这个木棍分成正整数长度的4段,其中有3段要没有不牢固的小木棍,勇太希望这3段木棍的长度和可以最大。同时六花希望在满足勇太要求的情况下让这三根木棍能拼成一个三角形,请问萌萌哒六花有多少种可行的分割方案呢?
当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗?
分析:先求出所有不牢固小木棍中最左边的位置L和最右边的位置R,可以确定的是其中一段一定是[L,R]。由于只有一段含有不稳定的,所以一定是L,R,自己写的时候就没想到
接着分两种情况考虑:
1.L=1或R=n
这样剩下的三段是由一整段木棒截来,我们可以枚举最左边一段的长度,这样可以得到一个关于第二段木棍的不等式,稍微讨论一下即可。
这里的讨论需要详细介绍一下
在这里,我们枚举最左边的线段长度为x1,如图
由组成三角形的条件可知
(x1+n-x1-x2)>x2 得x2<n/2,同样可得x1<n/2
x1+x2>n-x1-x2 得x2>n/2-x1
即有 n/2-x1<x2<n/2
则符合条件的x2的个数为(n-1)/2-(n/2-x1) //注意这里是小于不是小于等于,所以要多减个1
2.除了1以外的情况
这种情况相对容易,枚举是左边一段还是右边一段作为完整的一段,然后再枚举另外一段的切割点,判断是否合法,如果合法就使答案加一。
时间复杂度O(n+m)。
Hack点:1.没开long long。2.没有考虑到第一种情况或者第一种情况写错。3.直接尝试用O(n2)的暴力
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 using namespace std; 6 int l,r,x,n,m; 7 int ok(int a,int b,int c) 8 { 9 if(a<b) swap(a,b); 10 if(a<c) swap(a,c); 11 if(b+c>a) return true; 12 else return false; 13 } 14 long long calc2(int x,int y) 15 { 16 long long tot=0; 17 for(int i=1;i<x;i++) 18 if(ok(i,x-i,y)) tot++; 19 for(int i=1;i<y;i++) 20 if(ok(i,y-i,x)) tot++; 21 return tot; 22 } 23 long long calc1(int n) 24 { 25 long long tot=0; 26 for(int i=1;i<=n-2;i++) 27 if(2*i<n) 28 { 29 tot+=(n-1)/2-(n/2-i); 30 } 31 return tot; 32 } 33 int main() 34 { 35 while(scanf("%d%d",&n,&m)!=EOF) 36 { 37 l=n,r=1; 38 for(int i=1;i<=m;i++) 39 { 40 scanf("%d",&x); 41 l=min(l,x); 42 r=max(r,x); 43 } 44 if(r==n) printf("%lld ",calc1(l-1)); 45 else if(l==1) printf("%lld ",calc1(n-r)); 46 else printf("%lld ",calc2(l-1,n-r)); 47 } 48 return 0; 49 }