题目大意:

求将$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

Split Divisibilities (Project Euler 598)的更多相关文章

  1. Python练习题 049:Project Euler 022:姓名分值

    本题来自 Project Euler 第22题:https://projecteuler.net/problem=22 ''' Project Euler: Problem 22: Names sco ...

  2. Python练习题 041:Project Euler 013:求和、取前10位数值

    本题来自 Project Euler 第13题:https://projecteuler.net/problem=13 # Project Euler: Problem 13: Large sum # ...

  3. Python练习题 039:Project Euler 011:网格中4个数字的最大乘积

    本题来自 Project Euler 第11题:https://projecteuler.net/problem=11 # Project Euler: Problem 10: Largest pro ...

  4. [project euler] program 4

    上一次接触 project euler 还是2011年的事情,做了前三道题,后来被第四题卡住了,前面几题的代码也没有保留下来. 今天试着暴力破解了一下,代码如下: (我大概是第 172,719 个解出 ...

  5. Python练习题 029:Project Euler 001:3和5的倍数

    开始做 Project Euler 的练习题.网站上总共有565题,真是个大题库啊! # Project Euler, Problem 1: Multiples of 3 and 5 # If we ...

  6. Project Euler 9

    题意:三个正整数a + b + c = 1000,a*a + b*b = c*c.求a*b*c. 解法:可以暴力枚举,但是也有数学方法. 首先,a,b,c中肯定有至少一个为偶数,否则和不可能为以上两个 ...

  7. Project Euler 44: Find the smallest pair of pentagonal numbers whose sum and difference is pentagonal.

    In Problem 42 we dealt with triangular problems, in Problem 44 of Project Euler we deal with pentago ...

  8. project euler 169

    project euler 169 题目链接:https://projecteuler.net/problem=169 参考题解:http://tieba.baidu.com/p/2738022069 ...

  9. 【Project Euler 8】Largest product in a series

    题目要求是: The four adjacent digits in the 1000-digit number that have the greatest product are 9 × 9 × ...

随机推荐

  1. java_hibernate

    入门:http://jingyan.baidu.com/article/cbf0e500965a352eab289368.html 步骤1.查看是否hibernate支持:file-->plug ...

  2. RequireJS全面讲解

    异步模块定义(AMD)  谈起RequireJS,你无法绕过提及JavaScript模块是什么,以及AMD是什么. JavaScript模块只是遵循SRP(Single Responsibility  ...

  3. Difference between val() and text()

    .val() works on input elements (or any element with a value attribute?) and .text() will not work on ...

  4. Python测试Kafka集群(pykafka)

    生产者代码: # -* coding:utf8 *- from pykafka import KafkaClient host = 'IP:9092, IP:9092, IP:9092' client ...

  5. go get 下载的包放在哪里呢?

    有些问题,我以前都是似懂非懂,没有去弄个究竟!!!!! 这个习惯非常不好,搞得有些东西看似懂了,又不能百分之百说自己懂了,可能下次就弄不出来了,这样是不可取的. 不能有这种做事的风格. ------- ...

  6. 解决ie下载apk后更改后缀名为.zip的问题

    转自:http://www.cnblogs.com/niuniu/archive/2012/03/06/2381811.html 解决: 服务器添加MIME类型: application/vnd.an ...

  7. C++ 字符串分割函数 str_split

    void str_split(const std::string & src, const std::string & sep, std::vector<std::string& ...

  8. 使用Eclipse Memory Analyzer分析内存

    1 内存泄漏的排查方法 Dalvik Debug Monitor Server (DDMS) 是 ADT插件的一部分,当中有两项功能可用于内存检查 : ·    heap 查看堆的分配情况 ·     ...

  9. python基础 实战作业 ---Excel基本读写与数据处理

    代码地址如下:http://www.demodashi.com/demo/11650.html 看完本篇需要: 10min 作业练习需要: 0.5h~3h(依练习者对python熟悉程度而定) 看完本 ...

  10. 冲销会计凭证:FBRP与FB08的区别

    FBRA一般是用来对已经清帐的凭证进行冲销的,我们知道普通的冲销只要用FB08就可以了,但是对于已经被清帐和凭证,我们只能用FBRA来进行清帐,我们来按以下的没测试来做验证一下.STEP1:用F-22 ...