J Prime Game(数学,思维,拆分素因子)

在这里插入图片描述


题意:

在这里插入图片描述


分析:

因为是相乘,所以乘得结果的素因子即是原序列各元素的素因子,那么对于任意不同的素因子,则需要求得其在所有的 fac(i, j)——对应 [i, j] 中出现的次数,或者说给最终结果贡献了多少。

样例2为例,对于素因子 '2’
包括素因子’2’ 的数6, 4, 8, 12,其对应的位置下标分别为1, 5, 9, 10

对于第1个数 ‘6’:
贡献的区间有:[1,1]、[1,2]、… … [1,10],共10个

对于第5个数 '4‘:
先考虑向左延伸并以此数结尾的区间,因为素因子2贡献的包含第1个数’6’的区间已经计算完了,即向左只能延申到第2个数’7’,所以区间为:[2,5]、[3,5]、[4,5]、[5,5],共4个
在考虑向右延伸并以此数开头的区间,那么区间为:[5,5]、[5,6]、… … [5,10],共6个
那么此数贡献的区间则为:4*6=24个

以此类推

那么对于素因子 prime[i],序列中第 j 个包含 prime[i] 的数所贡献的区间个数为
ans[prime[i]][j]=(pos[prime[i]][j]pos[prime[i]][j1])(npos[prime[i]][j]+1)ans[prime[i]][j]=\left ( pos[prime[i]][j]-pos[prime[i]][j-1]\right )*\left ( n-pos[prime[i]][j]+1 \right )
其中pos[prime[i]][j]为序列中第 j 个包含素因子prime[i] 的数的位置

再者就是拆分素因子,要记录序列中共有哪些素因子,并记录包含它们的数的位置,这个可以用类似埃氏素筛法的方法进行操作,详见代码。



以下代码:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1e6+7;
int n,a[maxn];
vector<int> prime,pos[maxn];
bool vis[maxn]={false};
void dive(int x,int p)
{
    for(int i=2;i<=sqrt(x);i++)     //寻找素因子
    {
    	if(x%i==0)
    	{
    		pos[i].push_back(p);    //记录位置
    		if(!vis[i])             //记录素因子
    		{   
    			prime.push_back(i);
    			vis[i]=true;
			}
			while(x%i==0)     //这条语句是重点,思想上类似于埃氏素数筛选法
    			x/=i;         //例如i==2,进行此操作,这样之后4,6,8...就不会被当成素数了
    	}
    }
    if(x>1)      //还要对循环结束后的x进行考虑
    {
		pos[x].push_back(p);
		if(!vis[x])
		{
			prime.push_back(x);
    		vis[x]=true;
		}
	}
}
int main()
{
	for(int i=0;i<maxn;i++) 
		pos[i].push_back(0);   //令pos[i][0]=0
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        dive(a[i],i);      //拆分
    }
    LL ans=0;
    for(int i=0;i<prime.size();i++)
    {
        for(int j=1;j<pos[prime[i]].size();j++)
        {
            ans+=(LL)(pos[prime[i]][j]-pos[prime[i]][j-1])*(LL)(n-pos[prime[i]][j]+1);
            //注意两个相乘的数都要先转化为long long类型再相乘,不然会溢出
		}
	}
	printf("%lld\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章