分解数
(dec.cpp/c/pas)
【问题描述】
Dpstr学习了动态规划的技巧以后,对数的分解问题十分感兴趣。
Dpstr用此过程将一个正整数x分解成若干个数的乘积:一开始令集合A中只有一个元素x,每次分解时从A中取一个元素a并找出两个大于1且互质的整数p,q,要求pq=a,然后将a分解成两个元素p和q,也就是从A中删去a并加入p和q。Dpstr把正整数x用该过程能分解的次数的最大值称为x的分解数。
例如66的分解数为2,因为最多分解2次。一种分解过程为:一开始A={66},第1次将66分解为11×6,此时A={11,6},第2次将6分解为2×3,此时A={11,2,3},之后无法分解。还可以知道,11,2,3的分解数均为0,因为它们一开始就无法分解。
不过只分解一个数对Dpstr来说不够有趣。Dpstr生成了一个包含n个正整数的数列a1, a2,..., an,请你回答有多少对正整数(l,r)满足1≤l≤r≤n且lcm(al, al+1, ..., ar-1,ar)的分解数恰为k。其中lcm(al, al+1,..., ar-1, ar)表示数列从第l项到第r项的所有数的最小公倍数,特别地,当l=r时,lcm(al)=al。由于答案可能很大,只需输出满足条件的正整数对个数除以10,007的余数。
【输入格式】
输入文件名为dec.in。
第一行包含两个正整数n,k,意义如题目所示。
第二行包含n个用空格隔开的正整数,分别表示a1, a2,..., an。
【输出格式】
输出文件名为dec.out。
输出一行一个整数,表示满足条件的正整数对个数除以10,007的余数。
【输入输出样例1】
dec.in |
dec.out |
3 1 2 3 6 |
4 |
见选手目录下的dec/dec1.in和dec/dec1.ans。
【输入输出样例1说明】
考虑所有满足1≤l≤r≤4的正整数对(l,r):
1、对于(1,1),lcm(2)=2,分解数为0;
2、对于(2,2),lcm(3)=3,分解数为0;
3、对于(3,3),lcm(6)=6,分解数为1;
4、对于(1,2),lcm(2,3)=6,分解数为1;
5、对于(2,3),lcm(3,6)=6,分解数为1;
6、对于(1,3),lcm(2,3,6)=6,分解数为1。
其中,6的分解数为1是因为{6}可以分解为{2,3},之后无法分解。
因此共有3对正整数(l,r)满足条件。
【输入输出样例2】
dec.in |
dec.out |
10 2 2 3 2 6 15 5 5 5 2 3 |
29 |
见选手目录下的dec/dec2.in和dec/dec2.ans。
【输入输出样例3】
见选手目录下的dec/dec3.in和dec/dec3.ans。
【数据规模与约定】
对于20%的数据,1≤n≤10,1≤k≤5,1≤ai≤20;
对于40%的数据,1≤n≤100,1≤k≤10,1≤ai≤100;
对于60%的数据,1≤n≤1,000,1≤k≤1,000,1≤ai≤100,000;
对于100%的数据,1≤n≤1,000,000,1≤k≤5,000,000,1≤ai≤10,000,000。
题解:线性筛+乱搞
用线性筛筛出1e7内的所以质数,同时记录每个数最小的质因子。然后就可以O(loga[i])的将每个数进行质因数分解,每次都除掉当前数的最小值因子。
然后枚举区间的起点,可以随着终点的后移发现lcm是单调不降的。所以可以设两个指针,pos1表示f[l,r]>k的最靠前的位置,pos2表示f[l,r]>=k的区间最靠前的位置,然后每次答案+=(pos1-pos2+1),因为单调性所以每次指针只能向后移,不会向前移,有效的保证了科学的时间复杂度。
#include
#include
#include
#include
#include
#define N 1000003
#define p 10007
using namespace std;
int n,k,pd[N*10],prime[700003],minp[N*10];
int a[N],vis[700003],size,num[N][10],vis1[700003],ans;
void calc()
{
minp[1]=1;
for (int i=2;i<=10000000;i++) {
if (!pd[i]) {
prime[++prime[0]]=i;
minp[i]=prime[0];
}
for (int j=1;j<=prime[0];j++){
if (i*prime[j]>10000000) break;
minp[i*prime[j]]=j;
pd[i*prime[j]]=1;
if (i%prime[j]==0) break;
}
}
}
inline void add(int x,int v)
{
for (int i=1;i<=num[x][0];i++) {
int t=num[x][i];
if (vis[t]==0&&v==1) vis[0]++;
vis[t]+=v;
if (vis[t]==0&&v==-1) vis[0]--;
}
}
inline void add1(int x,int v)
{
for (int i=1;i<=num[x][0];i++) {
int t=num[x][i];
if (vis1[t]==0&&v==1) vis1[0]++;
vis1[t]+=v;
if (vis1[t]==0&&v==-1) vis1[0]--;
}
}
int main()
{
freopen("dec.in","r",stdin);
freopen("dec.out","w",stdout);
calc();
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++) {
scanf("%d",&a[i]);
int x=a[i];
while (x!=1) {
num[i][++num[i][0]]=minp[x];
int t=prime[minp[x]];
while (x%t==0) x/=t;
}
}
int l=0,r=0;
for (int i=1;i<=n;i++) {
while (vis[0]k+1) add1(--r,-1);
ans=(ans+(r-l+1))%p;
}
add(i,-1); add1(i,-1);
}
printf("%d\n",ans);
}