标签:des style blog io color ar os sp for
Description
Input
Output
Sample Input
1 2 3 4 5 6 8 9 10 11 12 15 19 20 100 1000
Sample Output
Case 1: 0 Case 2: 0 Case 3: 1 Case 4: 0 Case 5: 1 Case 6: 2 Case 7: 1 Case 8: 6 Case 9: 3 Case 10: 4 Case 11: 10 Case 12: 25 Case 13: 10 Case 14: 16 Case 15: 525236 Case 16: 523080925
思路:参考了:
1、本质三角形的定义:设a、b、c为三角形的三边,则gcd(a,b,c)=1。
2、先不考虑边互不互质,算出周长为i的三角形个数(动规实现,其实暴力应该也可以)。然后算周长为i,即
i个单位长度作边长的三角形的组合数。
a)你用隔板法考虑就是i个点,i-1个空格插隔板,djw[i]=2^(i-1)种;
b)你也可以按选与不选考虑。
注:放在一个格子里的三角形边长合并组成大边长的三角形。
最后就是n/i个周长为i的三角形组合数即为所求。
3、说一下用动态规划求dp[i]的过程:
函数dp(x),表示周长为 x的不同三角形(a,b,c)的数量,我们假设( a <= b <= c )
则我们通过枚举最大周长 x, 假设其最大边为 c.
则问题可以划分为两类独立: 1: b = c 2:b != c
第一种情况: b = c, 则周长为x的三角形 (a,c,c) 的方案数为:
因为 a+c+c = x , 且 a <= c 那么
c最大取 A=floor((x-1)/2 ), c最小取 B=ceil( x/3 ), 则此时三角形种类: A-B+1
第二种情况: b != c, 则周长为x的三角形 (a,b,c) 的方案数为:
因为 a+b+c = x, 且 b <= c-1,a+b > c,
这里, 我们转而考虑 , 形式如 ( a, b, c-1 ) 的三角形, 其方案数为 f( x-1 ),
因为 b <= c-1, 又 a+b > c-1,则当 a+b > c ,则其就是三角形 (a,b,c)下的不同三角形数量 f(x)了.
但是这里有个地方不满足, 就是当 a+b == c,的时候, 假设其为 M , 则我们就可以得出: f( x ) = f( x-1 ) - M , (b!=c).
问题就是如何计算出这个M, 我们继续考虑.
a+b+(c-1) = x-1,
=>a+b+c = x, 又因为 a+b = c. 可以得到
=> c+c = x , 2*c = x, 所以 c = x/2, 因为c为整数,所以我们知道,只有当x为偶数时才会出现这个M.
又 a + b = c = x/2, 且 a <= b , 此时 a 的取值为 [ 1, floor( (x/2)/2 ) ]
所以当 x为偶数时, M = floor( (x/2)/2 )
当 x为奇数时, M = 0;
dp[i]表示周长为i,那么就有n / i 个这样的三角形。用隔板板,将三角形合并成大的,保证相似就是2
^ (n / i - 1)种情况
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> typedef long long ll; using namespace std; const int maxn = 5000005; const int mod = 1000000007; int dp[maxn], num[maxn]; void init() { dp[3] = 1; for (int i = 4; i < maxn; i++) { dp[i] = dp[i-1] + floor((i-1)/2.0) - ceil(i/3.0) + 1; if (!(i & 1)) dp[i] -= i / 4; dp[i] %= mod; if (dp[i] < 0) dp[i] += mod; } num[1] = 1; for (int i = 2; i < maxn; i++) { num[i] = (num[i-1] << 1) % mod; for (int j = 2; i * j < maxn; j++) { dp[i * j] -= dp[i]; if (dp[i * j] < 0) dp[i * j] += mod; } } } int main() { int n, t, cas = 1; init(); while (scanf("%d", &n) != EOF) { ll ans = 0; for (int i = 1; i * i <= n; i++) { if (n % i) continue; ans = (ans + (1ll*dp[i]*num[n/i])) % mod; if (i * i != n) ans = (ans + (1ll*dp[n/i] * num[i])) % mod; } printf("Case %d: %lld\n", cas++, ans); } return 0; }
标签:des style blog io color ar os sp for
原文地址:http://blog.csdn.net/u011345136/article/details/40930379