1. 程式人生 > >Gym - 101981J The 2018 ICPC Asia Nanjing Regional Contest J.Prime Game 計數

Gym - 101981J The 2018 ICPC Asia Nanjing Regional Contest J.Prime Game 計數

題面

題意:1e6的陣列(1<a[i]<1e6),     mul (l,r) =l × (l+1) ×...× r,  fac(l,r) 代表 mul(l,r) 中不同素因子的個數,求sigma(i=1 to n) sigma(j=i to n) fac(i,j)

題解:計數套路題,算貢獻,直接算有多少區間包含某一個素數的倍數

記錄一下所有2的倍數的位置,3的倍數的位置,

    之後算有多少個區間包含2倍數的位置,這個就是2這個素數的倍數的貢獻,

    然後算有多少個區間包含3這個素數的倍數的位置,這個就是3這個素數的貢獻。

#include<bits/stdc++.h>
using namespace std;
#define mem(a,i) memset(a,i,sizeof(a))
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long ll;
const int maxn=1e6+5;
int a[maxn],n;
bool vis[1005];
int prim[1005];
vector<int> vec[maxn];
int cnt;
void
init() { mem(vis,0); rep(i,0,maxn-1) vec[i].clear(); cnt=0; rep(i,2,1004) { if(!vis[i]) { prim[++cnt]=i; for(int j=i*2;j<1005;j+=i) { vis[j]=1; } } } } int main() { init(); scanf("%d",&n); rep(i,
1,n) { scanf("%d",&a[i]); int temp=a[i]; rep(j,1,cnt) { if(temp<prim[j]) break; if(temp%prim[j]==0) { vec[prim[j]].pb(i); while(temp%prim[j]==0) temp/=prim[j]; } } if(temp!=1) vec[temp].pb(i); } ll ans=0; rep(i,2,maxn-1) { ll res=1ll*n*(n+1)/2; int len=vec[i].size(); if(len==0) continue; rep(j,0,len-1) { if(j==0) res-=1ll*(vec[i][j]-1)*(vec[i][j])/2; if(j==len-1) res-=1ll*(n-vec[i][j])*(n-vec[i][j]+1)/2; if(j+1<len) res-=1ll*(vec[i][j+1]-vec[i][j])*(vec[i][j+1]-vec[i][j]-1)/2; } ans+=res; } printf("%lld\n",ans); return 0; }