您的位置:首页 > 产品设计 > UI/UE

HDU 4390 Number Sequence

2016-05-10 20:11 435 查看
多校赛蛮难。。

这道题,二项式反演。。

来自仓鼠学长的博客

比如下面这个公式

f(n) = g(1) + g(2) + g(3) + … + g(n)

如果你知道g(x),然后你就可以知道f(n)了

如果我知道f(x),我想求g(n)怎么办

这个时候,就有反演定理了

反演定理可以轻松的把上面的公式变为

g(n) = f(1) + f(2) + f(3) + … + f(n)

这里用到的是二项式反演。。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <set>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
set < int > zhishu;
int all [1000000];//数组大小re了2次,而是醉了,题目明确指出了。。
ll c[100][30];
void build()//这里有20个数字,为了满足下面的公式所以我开了100,,因为10的25次方大约2的84次方
{
for(int i = 0 ; i <= 90 ; ++ i)
{
c[i][0] = 1;
for(int j = 1 ; j <= 20 ; ++ j)
{
c[i][j] = ( c[i-1][j] + c[i-1][j-1] ) % mod ;
}
}
}
int main()
{
int n;
build();
while(scanf("%d", &n) == 1)
{
int test;
zhishu.clear();
memset(all , 0 , sizeof(all));
for(int i = 1; i <= n ; ++i)
{
scanf("%d", &test);
for(int i = 2 ; i * i <= test ; ++ i)
{
if(test % i == 0)
{
int cnt = 0;
zhishu.insert(i);
while(test % i == 0)
{
++ cnt;
test = test / i;
}
all[i] += cnt;
}
}
if(test > 1)
{
zhishu.insert(test);
++all[test];
}
}
int flag = 1;
ll ans = 0;
for(int i = 0 ; i < n ; ++ i)//这就是二项式反演了, 一开始, 我的想法是容斥(事实是容斥最后的公式就是这个),当时队长大人讲的时候一脸懵逼,然后看了仓鼠学长的博客就解决啦。。!现在觉得二项式反演更加容易想到一点(。。)。。
{
ll nowall = c
[i];//这里本是 1;但是反正要乘c
[i],就先乘上好了。。
for(set<int>::iterator it = zhishu.begin(); it != zhishu.end() ; ++it)
{
nowall = ( nowall * c[all[*it] + n - i - 1][n - i - 1] ) % mod;//这里就是处理f(i)的时候,f(i)表示有几块不是空(g(i))的时候的总数,百度百科里面有很详细的解释。。 这一块发呆了2个小时也是醉了,高数靠前综合症。。
}
ans += ( flag * nowall ) % mod;
ans = ( ans + mod ) % mod;
flag = - flag;
}
cout << ans << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hdu 二项式反演 容斥