思路来源
rainboy代码的写法
一些OEIS链接
A066150 - OEIS,x位数最大的因子个数
知识点总结
1. 如何根据所有质因子,预处理所有因子?
根据约数定理,
对于,其约数个数
,
考虑新增一个数的增量贡献,
实际是
记
因此,可以令区间中下标
对应的数
,
从通过新增一个素因子
转移而来
// x=prod{v in x}, 获取x的每个因子值v,因子个数前缀积d
void get_d(vector<int>&x){
get_p(x);
v[0]=d[0]=1;
for(int i=0;i<c;++i){
d[i+1]=d[i]*(num[i]+1);
for(int j=d[i];j<d[i+1];++j){
v[j]=v[j-d[i]]*p[i];
}
}
}
2. 如何判断每个因子有哪些质因子?
每个长为的分区,前
个是不包含
的,后面的才是包含
的,
所以,遍历个质因子时,对于下标
对应的数
,
只有落到后半段,才表明
包含这个质因子
// x=prod{v in x}, 对于x的每个因子w,获取w的所有质因子pw的list,与下标对应
map<int,vector<int> >get_p_for_each_d(vector<int>&x){
get_d(x);
map<int,vector<int> >all;
for(int i=0;i<c;++i){
for(int j=0;j<d[c];++j){
if(j%d[i+1]>=d[i]){
all[v[j]].push_back(p[i]);
}
}
}
return all;
}
板子整理
c:质因子的个数
p:p[i]表示第i个质因子的值
num:num[i]表示第i个质因子的出现次数
d:d[i]表示前i个因子形成的因子个数,即因子个数前缀积
v:v[i]表示第i个因子值
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
struct Factor{
typedef long long ll;
static const int N=103680;// https://oeis.org/A066150
int p[N],num[N],d[N],c;
ll v[N];
map<int,int>fac;
Factor(){
init();
}
void init(){
c=0;
fac.clear();
}
// 质因数分解,视情况可以换为pollard_pho
void cal_f(int x){
for(int i=2;1ll*i*i<=x;++i){
while(x%i==0)x/=i,fac[i]++;
}
if(x>1)fac[x]++;
}
// x=prod{v in x},获取x的每个质因子值p,出现个数num
void get_p(vector<int>&x){
for(auto &v:x){
cal_f(v);
}
for(auto &w:fac){
p[c]=w.first;
num[c++]=w.second;
}
}
// x=prod{v in x}, 获取x的每个因子值v,因子个数前缀积d
void get_d(vector<int>&x){
get_p(x);
v[0]=d[0]=1;
for(int i=0;i<c;++i){
d[i+1]=d[i]*(num[i]+1);
for(int j=d[i];j<d[i+1];++j){
v[j]=v[j-d[i]]*p[i];
}
}
}
// x=prod{v in x}, 对于x的每个因子w,获取w的所有质因子pw的list,与下标对应
map<int,vector<int> >get_p_for_each_d(vector<int>&x){
get_d(x);
map<int,vector<int> >all;
for(int i=0;i<c;++i){
for(int j=0;j<d[c];++j){
if(j%d[i+1]>=d[i]){
all[v[j]].push_back(p[i]);
}
}
}
return all;
}
// 举个例子
void show_case(){
vector<int>x{10,15};
auto y=get_p_for_each_d(x);
for(auto &z:y){
cout<<"fi: "<<z.first<<" fac:";
for(auto &w:z.second){
cout<<w<<" ";
}
cout<<endl;
}
}
}f;
int main(){
f.show_case();
return 0;
}