http://acm.hdu.edu.cn/showproblem.php?pid=4472
看到这题,第一反应是找规律,写个暴力dfs看看有啥规律,实在看不出来,但是觉得这个暴力可以优化,加了个dp[]数组,过了,喜大普奔
第一次代码是这样的
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
LL dp[1005];
void dfs(int id,int N)
{
if(dp[N+1])
{
dp[id]=(dp[id]+dp[N+1])%mod;
return;
}
if(N==0)
{
dp[id]=(dp[id]+1)%mod;
return ;
}
for(int i=1;i<=N;i++)
{
if((N-i)%i==0)
{
dfs(id,(N-i)/i);
}
}
}
int main()
{
for(int N=1;N<=1000;N++)dfs(N,N-1);
int N,kkk=1;
while(~scanf("%d",&N))
{
printf("Case %d: %lld\n",kkk++,dp[N]);
}
return 0;
}
看起来比较臃肿,但比赛的时候想不了那么多了,过一个是一个。赛后又精简了一下
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
LL dp[1005];
LL dfs(int N)
{
if(dp[N+1])return dp[N+1];
for(int i=1;i<=N;i++)
if((N-i)%i==0)
dp[N+1]=(dp[N+1]+dfs((N-i)/i))%mod;
return dp[N+1];
}
int main()
{
int N,kkk=1;
dp[1]=1;
while(~scanf("%d",&N))
{
printf("Case %d: %lld\n",kkk++,dfs(N-1));
}
return 0;
}
后来又想了一下,其实很简单,可以直接用dp方程推,i个节点有dp[i]种排法,那么可以对于这种i个节点的树,可以拿k个出来,把他们的根节点连到同一个节点上去,形成一个ki+1个节点的树,这个树也是满足条件的,那么dp[ki+1]+=dp[i],初始值dp[1]=1,按素数筛那种写法,倒着推一遍就完事了。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
const int maxN=1e3+5;
int N,cas=1;
LL dp[maxN];
int main()
{
dp[1]=1;
for(int i=1;i<=1000;i++)
for(int k=1;k*i+1<=1000;k++)
dp[k*i+1]=(dp[k*i+1]+dp[i])%mod;
while(~scanf("%d",&N))printf("Case %d: %lld\n",cas++,dp[N]);
return 0;
}