题目大意:

求将$100!$ 拆成$a*b$的方案数,其中$a<=b$并且它们的约数个数一样多。

思路:

先将$100!$质因数分解, 结果如图:

首先想到一个暴力DP, dp[i][j][k]表示考虑完前i个质数, 目前a有j个约数,b有k个约数的方案数。 用map保存状态。

答案就是sum(dp[25][j][j]).

但是状态数会很多(大概有1e8个状态),所以考虑 中途相遇法。 对前3个质数做一次DP, 然后对后面22个质数做一次DP。

最后答案就是 sum (dp1[3][i1][j1] * dp2[22][i2][j2])   条件是 i1 * i2 = j1 * j2.  即  i1 / j1 =  j2 / i2 .

一个优化是只保存 j和k互质的状态。 然后 最后 答案的时候 枚举 i1,j1,  在 dp2中 查找 j2 / i2 = i1 / j1的点 。

因为a<=b,所以最后答案还需要除以2.

代码:

 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <set>
#include <cstring>
#include <map>
#include <queue>
using namespace std; typedef long long ll;
#define N 10000000
#define M 1100
typedef pair<int,int> pii; bool flag[N];
int p[N],phi[N]; struct node
{
ll x,y;
bool operator < (const node &t)const
{
return y*t.x<x*t.y;
}
node (ll _x = , ll _y = ){x = _x; y = _y;}
}; map<node, ll> mp; ll Gcd(ll x, ll y)
{
ll tmp;
while (y)
{
tmp = x % y;
x = y, y = tmp;
}
return x;
} void Get_Primes(int lim)
{
phi[]=;
for (int i=;i<=lim;i++)
{
if (!flag[i]) p[++p[]]=i,phi[i]=i-;
for (int j=;j<=p[] && i*p[j]<=lim;j++)
{
flag[i*p[j]]=true;
if (i%p[j]==)
{
phi[i*p[j]]=phi[i]*p[j];
break;
}
else phi[i*p[j]]=phi[i]*(p[j]-);
}
}
} map<pair<ll,ll>, ll> f[], g[];
int cnt[]; int main()
{
freopen("in.in","r",stdin);
freopen("out.out","w",stdout); int n = ;
Get_Primes(n);
for (int i = ; i <= p[]; ++i)
{
int x = p[i];
while (x <= n) cnt[i] += n / x, x *= p[i];
} f[][make_pair(,)] = ;
for (int i = ; i <= ; ++i)
{
for (map<pair<ll,ll>, ll>::iterator it = f[i - ].begin(); it != f[i - ].end(); it++)
{
ll k1 = (*it).first.first, k2 = (*it).first.second;
for (int j = ; j <= cnt[i]; ++j)
{
ll kx = k1 * (j + ), ky = k2 * (cnt[i] - j + ) , d = Gcd(kx, ky);
f[i][make_pair(kx / d, ky / d)] += (*it).second;
}
}
}
g[][make_pair(,)] = ;
for (int i = ; i <= p[] - ; ++i)
{
for (map<pair<ll,ll>, ll>::iterator it = g[i - ].begin(); it != g[i - ].end(); it++)
{
ll k1 = (*it).first.first, k2 = (*it).first.second;
for (int j = ; j <= cnt[i + ]; ++j)
{
ll kx = k1 * (j + ), ky = k2 * (cnt[i + ] - j + ), d = Gcd(kx, ky);
g[i][make_pair(kx / d, ky / d)] += (*it).second;
}
}
}
for (map<pair<ll,ll>, ll>::iterator it = g[p[] - ].begin(); it != g[p[] - ].end(); it++)
{
ll x = (*it).first.first, y = (*it).first.second;
mp[node(x, y)] += (*it).second;
} ll res = ;
for (map<pair<ll,ll>, ll>::iterator it = f[].begin(); it != f[].end(); it++)
{
ll x = (*it).first.first, y = (*it).first.second;
res += (*it).second * mp[node(y, x)];
}
cout << res / << endl;
return ;
}

答案:543194779059

最新文章

  1. JAVA判断当前日期是节假日还是工作日
  2. 实现loading动画效果
  3. v9 推荐位 排序问题解决办法
  4. JavaBean 内省API BeanUtils工具 泛型 xml xml约束
  5. Android 自定义View (二) 进阶
  6. HDFS文件读取详解
  7. 阿里云ECS每天一件事D6:安装nginx-1.6.2
  8. NotePad++ 配置C/C++编译环境
  9. PE结构之重定位表
  10. copy ,abs,includes 3个函数
  11. CONFIGURE ADFS 3.0 WITH SHAREPOINT 2013
  12. [android学习]__使用百度地图开放api编写地图定位app
  13. java常见错误总结
  14. 随机森林和GBDT的几个核心问题
  15. 数据库 -- Oracle常用命令
  16. JavaScript中的数据结构及实战系列
  17. 提取oracle awr报告
  18. ROS知识(5)----消息与服务的示例
  19. Myeclipse报错:“Versions of Spring facet could not be detected”的解决方法
  20. UITableView---iOS-Apple苹果官方文档翻译

热门文章

  1. Android 拍照、从相册获取及裁剪的相关实现
  2. PostgreSQL配置文件--连接和认证
  3. Spark(三) -- Shark与SparkSQL
  4. springmv日志debug异常,javax.naming.NameNotFoundException
  5. 倍福TwinCAT(贝福Beckhoff)基础教程7.1 TwinCAT如何简单执行NC功能块 TC2
  6. 在FASTBuild中使用Caching
  7. 网络编程基础——学习阻塞,非阻塞(select和epoll)
  8. 在LoadRunner中设置HTTP请求time-out的时间
  9. zoj 2744 - Palindromes
  10. WP8控件进度条(ProgressBar)的使用