题目:给你一根长度为n的铁丝,将铁丝分成几部分,再把每部分都折成三角形,并且每个三角形都相似,而且三角形的边长是整数。问有多少种分法。
三角形三遍相等视为相等,三角形顺序不同视为不同
思路:设三角形3边为a,b,c,并且a<=b<=c,
令dp[i]表示周长为i的三角形有多少个
考虑周长i:
如果b=c,那么c的最长是(i-1)/2,最短是(i+2)/3,那么新增加了(i-1)/2-(i+2)/3+1个三角形;
如果b<c,那么我们可以让c在周长为i-1的情况下增加1,那么就可以增加dp[i-1]个三角形,
注意,考虑现在的c,存在a+b=c的情况,这种情况要删去,i-1=a+b+c-1==>i=2*c,因此在i为偶数时要减去i/2/2
然后我们用筛法保证gcd(a,b,c)=1,然后就可以用插板的方法算分法数了,具体看代码
代码:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<list>
#include<numeric>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define PP puts("*********************");
template<class T> T f_abs(T a){ return a > 0 ? a : -a; }
template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
// 0x3f3f3f3f3f3f3f3f
// 0x3f3f3f3f
const LL MOD=1e9+7;
const int maxn=5e6+50;
int dp[maxn],num[maxn];
void init(int n){
dp[3]=1;
for(int i=4;i<=n;i++){
dp[i]=dp[i-1]+(i-1)/2-(i+2)/3+1;
if(i%2==0) dp[i]-=i/2/2;
if(dp[i]>=MOD) dp[i]-=MOD;
if(dp[i]<0) dp[i]+=MOD;
}
num[0]=1;
num[1]=2;
num[2]=4;
for(int i=3;i<=n;i++){//使得gcd(a,b,c)=1,为插板做准备
num[i]=num[i-1]*2;
if(num[i]>=MOD) num[i]-=MOD;
for(int j=2;j*i<=n;j++){
dp[i*j]-=dp[i];
if(dp[i*j]<0)
dp[i*j]+=MOD;
}
}
}
int main(){
int cas=0,n;
init(maxn-50);
while(~scanf("%d",&n)){
LL ans=0;
for(int i=1;i*i<=n;i++){
if(n%i!=0) continue;
ans=(ans+(LL)dp[i]*num[n/i-1]%MOD)%MOD;
if(i*i!=n)
ans=(ans+(LL)dp[n/i]*num[i-1]%MOD)%MOD;
}
printf("Case %d: %lld\n",++cas,ans);
}
return 0;
}