三角形顺序不同视为不同方案。
题解: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; }