hdu 4390 Number Sequence (容斥原理)

Number Sequence

Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 790    Accepted Submission(s): 331

Problem Description

Given a number sequence b1,b2…bn.

Please count how many number sequences a1,a2,...,an satisfy the condition that a1*a2*...*an=b1*b2*…*bn (ai>1).

Input

The input consists of multiple test cases.

For each test case, the first line contains an integer n(1<=n<=20). The second line contains n integers which indicate b1, b2,...,bn(1<bi<=1000000, b1*b2*…*bn<=1025).

Output

For each test case, please print the answer module 1e9 + 7.

Sample Input

2
3 4

Sample Output

4

Hint

For the sample input, P=3*4=12.
Here are the number sequences that satisfy the condition:
2 6
3 4
4 3
6 2

Source

2012 Multi-University Training Contest
10

题意:

求一个数列 a1,a2,..an,使a 1*a 2*...*a n=b 1*b 2*…*b n ,其中ai>1;

思路:

刚开始没什么思路,在网上找了很久,发现很多博客都是千篇一律的,后来总结了一下。。

1.先对每个bi跟姐质因数,用map保存每个因子出现的次数,此时ai*a2*...an的质因子为map保存的;

2.现在的问题就是将n个相同的数放进m个盒子里,假设盒子可为空,则所有情况为C(n+m-1,n-1),然后,对map里保存的因子个数逐个代入计算,

再应用乘法原理就可以求出盒子可为空时所有的情况。

3.题目要求盒子不可为空,这就要用到数学归纳法了:

f[i]-放入i个数能够为空的种数,g[i]-放入i个数不能为空的种数:

f[1]=g[1]

f[2]=g[2]+C(2,1)*g[1],

f[3]=g[3]+C(3,1)*g[2]+C(3,2)*g[1],

......

g[n]=f[n]-C(n,1)*f[n-1]+C(n,2)*f[n-2]-...

依次计算有i个盒子为空的组合数,应用容斥原理:-g[1]+g[2]-g[3]+g[4]....;

My Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#include<map>

#define N 100010
#define mod 1000000007
#define lson l,mid,idx<<1
#define rson mid+1,r,idx<<1|1
#define lc idx<<1
#define rc idx<<1|1
const double EPS = 1e-11;
const double PI = acos(-1.0);
const double E=2.718281828;
typedef long long ll;

const int INF=1000010;

using namespace std;

int C[1001][45];///组合数
map<int,int>mp;

void init()
{
    for(int i=0; i<=1000; i++)
        C[i][0]=1;///i个选0个为1;
    for(int i=1; i<=1000; i++)
        for(int j=1; j<=42; j++)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;///c(n,k)=c(n-1,k)+c(n-1,k-1),可以自己证明
}

void Fenjie(int n)///分解质因数
{
    for(int i=2; i*i<=n; i++)
    {
        if(n%i==0)
        {
            while(n%i==0)
            {
                mp[i]++;
                n/=i;
            }
        }
        if(n==1)
            break;
    }
    if(n>1)
        mp[n]++;
}

int main()
{
    init();
    int n;
    while(cin>>n)
    {
        mp.clear();
        int b;
        for(int i=0; i<n; i++)
        {
            scanf("%d",&b);
            Fenjie(b);
        }
        ll ans=0;
        for(int i=0; i<n; i++)///容斥原理
        {
            ll tem=C[n][i];
            map<int,int>::iterator it;
            for(it=mp.begin(); it!=mp.end(); it++)///计算有i个盒子为空的组合数
            {
                int t=it->second+n-i-1;
                tem*=C[t][n-i-1];
                tem%=mod;
            }
            if(i%2)
                ans-=tem,ans+=mod;
            else
                ans+=tem;
            ans%=mod;
        }
        cout<<ans%mod<<endl;
    }
    return 0;
}

时间: 2024-08-28 03:35:15

hdu 4390 Number Sequence (容斥原理)的相关文章

HDU 4390 Number Sequence (容斥原理+组合计数)

HDU 4390 题意: 大概就是这样.不翻译了: Given a number sequence b1,b2-bn. Please count how many number sequences a1,a2,...,ansatisfy the condition thata1?a2?...?an=b1?b2?-?bn(ai,bi>1). 思路: 我们能够确定一件事:等号两边由同样数量的质因子组成. 假设ai能够等于1,答案就是把这些质因子分配进n个位置的方案数. 设左边的数字共由x个质因子组成

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> #in

HDU 5014 Number Sequence(2014 ACM/ICPC Asia Regional Xi&#39;an Online) 题解

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5014 Number Sequence Problem Description There is a special number sequence which has n+1 integers. For each number in sequence, we have two rules: ● ai ∈ [0,n] ● ai ≠ aj( i ≠ j ) For sequence a and sequ

KMP算法的定义及KMP练手题 HDU 1711 Number Sequence (我的模板代码)

题意:就是要你来找出b数组在a数组中最先匹配的位置,如果没有则输出-1 思路:直接KMP算法(算法具体思想这位牛写的不错http://blog.csdn.net/v_july_v/article/details/7041827) AC代码: #include<cstdio> #include<cstring> #include<stdlib.h> #include<iostream> using namespace std; #define maxn 100

hdu 5014 Number Sequence(贪心)

题目链接:hdu 5014 Number Sequence 题目大意:给定n,表示有0~n这n+1个数组成的序列a,要求构造一个序列b,同样是由0~n组成,要求∑ai⊕bi尽量大. 解题思路:贪心构造,对于n来说,找到n对应二进制的取反对应的数x,那么从x~n之间的数即可两两对应,然后x-1即是一个子问题. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; con

HDU 5014 Number Sequence(西安网络赛H题)

HDU 5014 Number Sequence 题目链接 思路:对于0-n,尽量不让二进制中的1互相消掉就是最优的,那么只要两个数只要互补就可以了,这样每次从最大的数字,可以找到和他互补的数字,然后这个区间就能确定了,然后剩下的递归下去为一个子问题去解决 代码: #include <cstdio> #include <cstring> const int N = 100005; int n, a[N], ans[N]; int cnt[N]; int count(int x) {

hdu 1711 Number Sequence(KMP)

# include <stdio.h> # include <string.h> # include <algorithm> using namespace std; int n,m,next[10010],a[1000010],b[10010]; void Getnext() { int i=0,j=-1; next[0]=-1; while(i<m) { if(j==-1||b[i]==b[j]) i++,j++,next[i]=j; else j=next[

HDU 1711 Number Sequence KMP题解

KMP查找整数数列,不是查找字符串. 原理是一样的,不过把字符串转换为数列,其他基本上是一样的. #include <stdio.h> #include <string.h> const int MAX_N = 1000001; const int MAX_M = 10001; int strN[MAX_N], strM[MAX_M], next[MAX_M], N, M; void getNext() { memset(next, 0, sizeof(int) * M); for

HDU - 1711 Number Sequence KMP字符串匹配

HDU - 1711 Number Sequence Time Limit: 5000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Submit Status Description Given two sequences of numbers : a[1], a[2], ...... , a[N], and b[1], b[2], ...... , b[M] (1 <= M <= 10000, 1 <=