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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章