HDU 4390 Number Sequence

多校赛蛮难。。
这道题,二项式反演。。

来自仓鼠学长的博客
比如下面这个公式

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[n][i];//这里本是 1;但是反正要乘c[n][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,容斥,二项式反演)