Educational Codeforces Round 33 E. Counting Arrays

来源:互联网 发布:noi linux 字体 变大 编辑:程序博客网 时间:2024/06/06 18:59

原题:
E. Counting Arrays
time limit per test3 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
You are given two positive integer numbers x and y. An array F is called an y-factorization of x iff the following conditions are met:

There are y elements in F, and all of them are integer numbers;
.这里写图片描述
You have to count the number of pairwise distinct arrays that are y-factorizations of x. Two arrays A and B are considered different iff there exists at least one index i (1 ≤ i ≤ y) such that Ai ≠ Bi. Since the answer can be very large, print it modulo 109 + 7.

Input
The first line contains one integer q (1 ≤ q ≤ 105) — the number of testcases to solve.

Then q lines follow, each containing two integers xi and yi (1 ≤ xi, yi ≤ 106). Each of these lines represents a testcase.

Output
Print q integers. i-th integer has to be equal to the number of yi-factorizations of xi modulo 109 + 7.

Example
input
2
6 3
4 2
output
36
6
Note
In the second testcase of the example there are six y-factorizations:

{ - 4,  - 1};
{ - 2,  - 2};
{ - 1,  - 4};
{1, 4};
{2, 2};
{4, 1}.

中文:
给你一个数n,表示有n个数据
然后输入x和y,问你y个数相乘等于x的方案数有多少种?

#include<bits/stdc++.h>using namespace std;typedef long long LL;const int maxn=1e6+50;const LL mod=1000000007;int p[2000];bool tag[20000];int ind;void get_prime(){    int cnt=0;    for(int i=2;i<2000;i++)    {        if(!tag[i])            p[cnt++]=i;        for(int j=0;j<cnt&&p[j]*i<2000;j++)        {            tag[i*p[j]]=1;            if(i%p[j]==0)                break;        }    }    ind=cnt;}LL quick_mod(LL a, LL b){    LL ans = 1;    a %= mod;    while(b)    {        if(b & 1)        {            ans = ans * a % mod;            b--;        }        b >>= 1;        a = a * a % mod;    }    return ans;}LL factor[maxn],inverse[maxn],pow2[maxn];void ini(){    get_prime();    factor[0]=1;    pow2[0]=1;    for(int i=1;i<maxn;i++)    {        factor[i]=factor[i-1]*i%mod;        pow2[i]=pow2[i-1]*2%mod;    }    inverse[maxn-1]=quick_mod(factor[maxn-1],mod-2)%mod;    for(int i=maxn-2;i>=0;i--)        inverse[i]=inverse[i+1]*(i+1)%mod;}LL C(LL n,LL m){    if(n<m)        return 0;    if(n<2*m)        m=n-m;    return factor[n]*inverse[n-m]%mod*inverse[m]%mod;}LL x,y;int main(){    ios::sync_with_stdio(false);    ini();    int n;    cin>>n;    while(n--)    {        LL ans=1;        cin>>x>>y;        int i=0,cnt=0;        while(i<ind)        {            if(p[i]>x)                break;            while(x%p[i]==0)            {                cnt++;                x/=p[i];            }            if(cnt>0)                ans=ans*C(y-1+cnt,cnt)%mod;            i++;            cnt=0;        }        if(x!=1)            ans=ans*y%mod;        ans=(ans*pow2[y-1])%mod;        cout<<ans<<endl;    }    return 0;}

解答:

首先用唯一分解定理,把x分解
x=p1a1×p2a2×p3a3....
例如
100=22×52

现在是要x分成y个数相乘的形式,相当于把每个素数因子放入y个不同盒子里,有多少种放置的方法。
相当于把n个一样的球,放到m个不同的盒子中,且盒子不为空。公式为(ai+y1ai)

因为有负数因子的存在,所以需要把结果乘以(y0)+(y2)+(y4)+....

接下来问题来了,由于数据x和y为10^6,而且还是一次输入多个数据进行计算。
如何快速求出组合数是个问题。
使用lucas公式,可是取模的数值是10^9+7,太大~
试了一下,果然超时,卡在第16组数据上了

后来看别人的代码,在计算组合数的时候都用了数组去记录一个值,研究后发现了一个叫乘法逆元的东西,曾经遇到过但是没注意。

基本意思就是计算组合数公式的方法m!n!×(mn)!

如果,在计算组合数的时候直接取模,即:
m!%modn!%mod×(mn)!%mod
上面公式是错误的!!!!!

加法、减法、乘法在进行余数计算的时候支持对余数四则运算,但是除法不能这样处理

解决办法是使用乘法逆元,类似于除以一个数等于乘以这个数的倒数的原理,只不过这里有了取模的条件
所谓乘法逆元,就是计算此公式ax1modp中的x是多少

推导过程使用了费马小定理
费马小定理为xpx(modp)
如果p不是x的因子
那么可以约掉一个x
xp11(modp)
可以写成
xp2x1(modp)
那么,要求的a就等于xp2,使用快速幂即可

由于是计算阶乘逆元,可以使用递推的方法来计算,否则挨个使用快速幂计算通常超时!

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 雍正珐琅彩瓷器底款 乾隆珐琅彩瓷器图片 故宫藏珐琅彩瓷 彩田 嫡女华第 彩田 庶女继妃 彩田 彩田桶装水 末世之女配崛起 彩田 彩电塔夜市 oled彩电 彩电网 彩电主板价格 创维彩电50e6000 彩电买什么牌子好 电信电视机顶盒 数字电视接收机 海信48寸液晶电视 120寸电视 酷开电视机 互联网电视和智能电视的区别 模卡电视 海信32寸液晶电视 海信led50k220 液晶电视硬屏和软屏的区别 海信48k220 海信65寸电视 海信3d电视 海信液晶电视机 海信55寸液晶电视 海信uled电视 电视机大小与观看距离 50英寸电视观看距离 大家电 海信40寸液晶电视 电视小锅 买电视机 老电视机 电视品牌 d55a561u 电视高压包 32寸液晶电视尺寸