hdu4466 将长度为n线段瓜分成若干个相似三角形,有多少种分法(划分dp)

hdu4466 将长度为n线段瓜分成若干个相似三角形,有多少种分法(划分dp)_第1张图片三角形顺序不同视为不同方案。

题解:http://www.cnblogs.com/jianglangcaijin/p/3465526.html

#include<bits/stdc++.h>
#define ll long long  
#define mod 1000000007
#define maxn 5000000
using namespace std;   
int dp[maxn+5];
int power[maxn+5];
int main(){
	power[0]=1;
	for(int i=1;i<=maxn;++i)
		power[i]=power[i-1]*2%mod;
	dp[3]=1;
	for(int i=4;i<=maxn;++i){ 
		dp[i]+=(i-1)/2-ceil(i/3.0)+1; //b=c:最少时靠近等边三角形,最多时最短边靠近1 
		dp[i]+=dp[i-1]; //b<c:不考虑c保底的1,(a,b,c)在b<c时的个数=(a,b,c-1)的总个数再减去 
		//a+b=(c-1)+1时(a,b,c-1)还原后取不到三角形时的个数,因为a+b+c=i,所以化简得c=i/2。 
		if(i%2==0)
			dp[i]=dp[i]-(i/2)/2+mod; //因为a+b已经确定,所以ab的取法只有floor(c/2)
		dp[i]%=mod;
	}
	//枚举最小的三角形的周长可能取值,会发现gcd(a0,b0,c0)=1,因为要保证其它都是它的倍数 
	//不然的话(6,9,9)不会是(4,6,6)的倍数,而应该是(2,3,3) 
	//因此,首先要预处理,把dp[]里面那些gcd!=1的情况去掉。这里用了一种类似筛选法的方法。
	for(int i=3;i<=maxn;++i){
		for(int j=i*2;j<=maxn;j+=i)
			dp[j]=(dp[j]-dp[i]+mod)%mod;
	} 
	int n,cnt=0;
	while(scanf("%d",&n)!=EOF){
		ll s=0;
		for(int i=1;i*i<=n;++i){ //枚举最小的单位三角形的周长可能取值
			if(n%i==0){
				int w=n/i-1; // n/i颗球有n/i-1个缝隙 
				s=(s+(ll)power[w]*dp[i])%mod; //Cn0-Cn1+Cn2-Cn3+……+(-1)^nCnn=0
				
				if(i*i!=n){
					w=i-1;  
					s=(s+(ll)power[w]*dp[n/i])%mod; //Cn0-Cn1+Cn2-Cn3+……+(-1)^nCnn=0
				}
			}
		}	
		printf("Case %d: %I64d\n",++cnt,s);
	}
	return 0;
} 


你可能感兴趣的:(hdu4466 将长度为n线段瓜分成若干个相似三角形,有多少种分法(划分dp))