Codeforces 893E Counting Arrays:dp + 线性筛 + 分解质因数 + 组合数结论

题目链接:http://codeforces.com/problemset/problem/893/E

题意:

  共q组数据(q <= 10^5),每组数据给定x,y(x,y <= 10^6)。

  问你有多少种长度为y,乘积为x的整数数列。(可以有负数)

题解:

  首先考虑数列只有正整数的情况。

  将x分解质因数:x = ∑ a[i]*p[i]

  由于x较大,所以要先用线性筛求出素数,再枚举素数分解质因数。

  那么一个乘积为x的数列可以看做,将x的所有∑ p[i]个质因子,分配到了y个位置上。

  设f(i)表示:将p[i]个质因子a[i],分配到y个位置上的方案数。

  所以乘积为x的数列总数ans = ∏ f(i)。

  其中,f(i)等价于:长度为y,和为p[i]的数列总数。

  由于是多组数据,所以要预处理出对于所有长度的f(i)。

  dp[i][j]表示y = i时,之和为j的数列总数。

  转移:dp[i][j] = ∑ dp[i-1][0 to j]

  用前缀和优化转移,总复杂度O(nlogn)。

  这样就求出了只考虑正整数情况下的数列总数:ans = ∑ dp[y][p[i]]

  然后考虑加负号的情况。

  由于x为正数,所以只能加偶数个负号。

  所以加负号的方案数 = C(y,0) + C(y,2) + C(y,4) + ... + C(y,偶数)

  有一个组合数结论:∑ C(n,偶数) = ∑ C(n,奇数) = 2^(n-1)。

  所以最终ans = ans * (2^(y-1))即为最终答案。

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define MAX_X 1000005
 5 #define MAX_P 25
 6 #define SET_X 1000000
 7 #define SET_P 20
 8 #define MOD 1000000007
 9
10 using namespace std;
11
12 int x,y,q;
13 int cnt,tot=0;
14 int p[MAX_P];
15 int pw[MAX_X];
16 int prime[MAX_X];
17 int dp[MAX_X][MAX_P];
18 int sum[MAX_X][MAX_P];
19 bool mark[MAX_X];
20
21 void cal_dp()
22 {
23     memset(dp,0,sizeof(dp));
24     memset(sum,0,sizeof(sum));
25     dp[0][0]=1;
26     for(int i=0;i<=SET_P;i++) sum[0][i]=1;
27     for(int i=1;i<=SET_X;i++)
28     {
29         for(int j=0;j<=SET_P;j++)
30         {
31             dp[i][j]=sum[i-1][j];
32             sum[i][j]=(sum[i][j-1]+dp[i][j])%MOD;
33         }
34     }
35 }
36
37 void cal_pw()
38 {
39     pw[0]=1;
40     for(int i=1;i<=SET_X;i++) pw[i]=(pw[i-1]<<1)%MOD;
41 }
42
43 void sieve()
44 {
45     memset(mark,false,sizeof(mark));
46     for(int i=2;i<=SET_X;i++)
47     {
48         if(!mark[i]) prime[++tot]=i;
49         for(int j=1;j<=tot && (long long)i*prime[j]<=SET_X;j++)
50         {
51             mark[i*prime[j]]=true;
52             if(!(i%prime[j])) break;
53         }
54     }
55 }
56
57 void resolve()
58 {
59     int t=x;
60     cnt=0;
61     memset(p,0,sizeof(p));
62     for(int i=1;i<=tot && prime[i]*prime[i]<=x;i++)
63     {
64         if(t%prime[i]==0)
65         {
66             cnt++;
67             while(t%prime[i]==0)
68             {
69                 t/=prime[i];
70                 p[cnt]++;
71             }
72         }
73     }
74     if(t!=1) p[++cnt]=1;
75 }
76
77 int cal_ans()
78 {
79     resolve();
80     long long ans=1;
81     for(int i=1;i<=cnt;i++) ans=ans*dp[y][p[i]]%MOD;
82     return ans*pw[y-1]%MOD;
83 }
84
85 int main()
86 {
87     sieve();
88     cal_dp();
89     cal_pw();
90     cin>>q;
91     while(q--)
92     {
93         cin>>x>>y;
94         cout<<cal_ans()<<endl;
95     }
96 }

原文地址:https://www.cnblogs.com/Leohh/p/8480257.html

时间: 2024-10-01 08:11:46

Codeforces 893E Counting Arrays:dp + 线性筛 + 分解质因数 + 组合数结论的相关文章

Codeforces 893E - Counting Arrays

893E - Counting Arrays 思路:质因子分解. 对于每个质因子,假设它有k个,那么求把它分配到y个数上的方案数. 相当于把k个小球分配到y个盒子里的方案数. 这个问题可以用隔板法(插空法)解决,要把一段分成y段,需要y-1个隔板,那么有y-1+k个位置,选y-1个位置为隔板,剩下的都是小球,那么方案数为C(y-1+k,y-1). 如果全为正数,答案就是所有质因子方案数的积. 但是这道题目可以为负数,那么在这y个数里选偶数个变成负数 答案还要乘以C(y,0)+C(y,2)+C(y

【BZOJ-4514】数字配对 最大费用最大流 + 质因数分解 + 二分图 + 贪心 + 线性筛

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 726  Solved: 309[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在

Educational Codeforces Round 37-F.SUM and REPLACE (线段树,线性筛,收敛函数)

F. SUM and REPLACE time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard output Let D(x) be the number of positive divisors of a positive integer x. For example, D(2)?=?2 (2 is divisible by 1 and 2), D(6)?

【Educational Codeforces Round 37】F. SUM and REPLACE 线段树+线性筛

题意 给定序列$a_n$,每次将$[L,R]$区间内的数$a_i$替换为$d(a_i)$,或者询问区间和 这题和区间开方有相同的操作 对于$a_i \in (1,10^6)$,$10$次$d(a_i)$以内肯定可以最终化为$1$或者$2$,所以线段树记录区间最大值和区间和,$Max\le2$就返回,单点暴力更新,最后线性筛预处理出$d$ 时间复杂度$O(m\log n)$ 代码 #include <bits/stdc++.h> using namespace std; typedef long

分解质因数(线性筛)

https://ac.nowcoder.com/acm/contest/923/B 我真是个辣鸡,现在才知道线性筛, 思路:对于每个数字的阶乘,开一个一维数组记录每个数字出现的个数,先利用一维差分将每个数字的阶乘中出现都得数字累加个数,然后再利用线性筛中,已知每个数字的最小质因数是什么,在比较过程中,我们可以从大到小比较,如果发现对于同一个数字它的出现次数不同,我们可以把这个数字划分为两个数字的乘积形式(已知每个数字的最小质因数都是固定的),如果数字相同就不用管了,最后在遍历一遍看看是否每个位置

bzoj 3309 DZY Loves Math - 莫比乌斯反演 - 线性筛

对于正整数n,定义f(n)为n所含质因子的最大幂指数.例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0. 给定正整数a,b,求sigma(sigma(f(gcd(i,j)))) (i=1..a, j=1..b). Input 第一行一个数T,表示询问数. 接下来T行,每行两个数a,b,表示一个询问. Output 对于每一个询问,输出一行一个非负整数作为回答. Sample Input 4 7558588 9653114 6514903 445

[原博客] 关于线性筛

埃氏筛法:从2开始,找到第一个没有被筛的数,把它标记为素数,然后把它的2倍.3倍……筛掉.复杂度O(nlogn). 改进的埃氏筛法:从2开始,找到第一个没有被筛的数x,把它标记为素数,然后把它的x倍.x+1倍……筛掉.复杂度O(nloglogn). 线性筛:保证每个数都被它的最小素因子筛掉.复杂度O(n). C++写起来大概是这样的: int mindiv[10000005],tot,prime[10000050]; int main(){ for(int i=2;i<=10000000;i++

[zroj 51] [Pendulum] : 线性筛

问题描述 Evan 站在巨大的世纪钟摆前,观察着钟摆上方数字的塌缩.他发现,钟摆每摆动?次,上方的数字就会变成把它分解质因数后每一项的和.例如 12 =2 × 2 × 3,那么摆动一次后数字变成 2 + 2 + 3 = 7.现在,上方的数字正好是 x.Evan 还有 y 秒就要去新世界探索了,他想知道在钟摆摆动 y 次到他离开时,上方的数字是多少. 输入格式 第一行一个整数n,表示询问个数.后面n行每行两个整数x和y. 输出格式 n行,每行一个答案表示离开时上方的数字. 样例输入 2 5 3 2

[bzoj2440]完全平方数[中山市选2011][莫比乌斯函数][线性筛][二分答案]

题意:求第k个分解质因子后质因子次数均为一的数,即求第k个无平方因子数. 题解: 首先二分答案mid,那么现在就是要求出mid以内的无平方因子数的个数. 其次枚举$\sqrt{mid}$内的所有质数,由容斥原理 $Num=0个质数平方的倍数的数量(1的倍数)-1个质数平方的倍数的数量(9,25...的倍数)$ $+2个质数平方的倍数的数量(36,100...的倍数)...$ 可以发现对于一个数x,x的倍数数量对答案的贡献符号为$\mu(x)$. 例如:9的倍数数量最答案的贡献是$\mu(9)\l