[Gym-101981J] Prime Game (計數)

 

 

題意:求for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) sum += f[i][j]; f[i][j]表示在序列從 i 位乘到第 j 位所造成的新的數的 不一樣質因子的個數.ios

思路:說是話,拿到題仍是一開始想着能不能進行遞推,好比先將每個數進行 質因分解 而後用set不斷更新統計個數來求和。但這樣不管怎樣都沒法優化 (n^2) ,因此換思路再想。c++

就突然想到了之前有一道作過的原題,題意是:給定一個長度爲n的序列,而後求出每個子區間不一樣數的個數和。而這一道題就是組合計數,計算每個位置上的值對最後區間計數所產生的貢獻。函數

而這道題相似,略微修改便是每個位置上不僅一個值(分解可能獲得多個質因子),因此就用set來存放。優化

上面這幅圖,座標軸上表示座標,座標軸下表示每一個位置set所存放對應數的質因子數。好比咱們對全部位置的5的貢獻值進行計算。spa

位置座標2:因爲這個5要產生貢獻,即其左邊起始下標要從 1 開始,直到它自己的座標 2. 其右邊的開始座標從它自己開始 2 一直延申到座標軸右端. 因此 左 x 右 = (2-0) x (7-2+1) = 10;code

位置座標4:要使這個位置的5產生貢獻,因爲咱們對上一個5右邊全部區間進行了計算,因此在計算這個5的貢獻的時候咱們要從它上一個5的位置的下一位開始到它自己,即從 3-4,而其右端也是延申到右端點,因此 (4-2) x (7-4+1) = 8;blog

因此計算某個數的貢獻,即 其左邊第一個出現的下一位開始到他自己位置爲左端點取值範圍,從他自己開始到座標軸右端點爲其區間右端點取值範圍,而左乘以右則爲全部區間貢獻總和。ci

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(0); cin.tie(0);
#define mp make_pair
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const double Pi = acos(-1.0);
const double esp = 1e-9;
const int inf = 0x3f3f3f3f;
const int maxn = 1e5+7;
const int maxm = 1e6+7;
const int mod = 1e9+7;
//全部模板默認 prime[],powe[]從下標0開始取
const int MAXL = 1e6+7;
//int phi[MAXL];//歐拉函數
int tot;
int prim[MAXL];//素數表
int cnt;
int vis[MAXL];
//int powe[MAXL];//質數冪
int cur;
int pp[maxm];

set<int>qq[maxm];
set<int>::iterator it;
int a[maxm];
int getPrime(){
    int i ,j;
    int cnt = 0;
    memset(vis,0,sizeof(0));
    vis[0] = vis[1] = 1;
    for(i=2;i<=MAXL;++i)
    {
        if(!vis[i]) vis[i]= prim[cnt++]= i;
        for(j=0;j<cnt&&i*prim[j]<=MAXL;++j){
            vis[i*prim[j]] = 1;
            if(i%prim[j]==0) break;
        }
    }
    return cnt;
}
int getfac(int n,int cnt,int pos){
    for(int i=0;prim[i]*prim[i]<=n;i++){
        if(n%prim[i]==0) {
            qq[pos].insert(prim[i]);
            pp[prim[i]] = 0;
            while(n%prim[i]==0) n /= prim[i];
        }   
    }
    if(n>1) qq[pos].insert(n);
}
int main(){
    int n;
    scanf("%d",&n);
    cnt = getPrime();
    for(int i=1;i<=n;i++){
        scanf("%d",a+i);
        getfac(a[i],cnt,i);
    }
    ll sum = 0;
    for(int i=1;i<=n;i++){
        for(it = qq[i].begin();it != qq[i].end(); it++){
            int tmp = *it;
            int k = pp[tmp];
            pp[tmp] = i;
            sum += (ll) (i-k)*(n-i+1);
        }
    }
    printf("%lld\n",sum);

} 
相關文章
相關標籤/搜索