【ACM-ICPC 2018 南京現場賽 】 J.Prime Game ---- 思維+素數篩
阿新 • • 發佈:2019-02-08
題目:
做法: 計算出來每個數的質因子在各個區間的貢獻。
以第二組樣例為例:
第一個元素的素因子2:
它能貢獻的區間有[1,1],[1,2],……,[1,10] 10個區間
第一個元素的素因子3:
它能貢獻的區間有[1,1],[1,2],……,[1,10] 10個區間
當前sum = 10+10
第二個元素的素因子7:
它能貢獻的區間有[1,2],[1,3],……,[1,10] 9個區間
它能貢獻的區間有[2,2],[2,3],……,[2,10] 9個區間
當前sum = 10+10 +9*2
同理第三個元素的素因子5算好後 sum = 10+10+9*2+8*3
當考慮第四元素的素因子5時,發現i = 3時的素因子5
在區間:
[1,3],[1,4],……,[1,10]
[2,3],[2,4],……,[2,10]
[3,3],[3,4],……,[3,10]
這3*8個區間中已經貢獻過,所以我們從當前i = 4位置向後考慮 這個位置的素因子5對區間的貢獻為 7
sum = 10+10+9*2+8*3+7
最終到n = 10,sum = 10+10+9*2+8*3+7+6*4+5*5+4+0+2*4+1+3=134
依次向後推理,我們現在每個素因子i貢獻公式為:
所以我們分解出質因子,把他們的位置放進vector, 掃一遍素數即可
程式碼
#include<bits/stdc++.h>
using namespace std;
#define IO ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define pb(x) push_back(x)
#define sz(x) (int)(x).size()
#define sc(x) scanf("%d",&x)
#define abs(x) ((x)<0 ? -(x) : x)
#define all(x) x.begin(),x.end()
#define mk(x,y) make_pair(x,y)
#define fin freopen("in.txt","r",stdin)
#define fout freopen("out.txt","w",stdout)
typedef long long ll;
const int mod = 1e9+7;
const double PI = 4*atan(1.0);
const int maxm = 1e8+5;
const int maxn = 1e4+5;
const int INF = 0x3f3f3f3f;
const ll LINF = 1ll<<62;
int a[maxn],n,tot;
int prime[maxn];
bool isprime[maxn];
vector<int> vec[maxn];
void prime_table()
{
memset(isprime,true,sizeof(isprime));
isprime[0] = isprime[1] = false;
for(int i=2;i<maxn;i++){
prime[tot++] = i;
if(isprime[i]){
for(int j=i*i;j<maxn;j+=i)
isprime[j] = false;
}
}
}
void dec(int pos)
{
int t = a[pos];
for(int j=0;j<tot && prime[j]*prime[j]<=t;j++)
{
if(t%prime[j] == 0){
vec[prime[j]].pb(pos);
while(t%prime[j] == 0) t/=prime[j];
}
}
if(t>1) vec[t].pb(pos);
}
int main()
{
// fin;
IO;
prime_table();
cin>>n;
for(int i=2;i<maxn;i++) vec[i].pb(0);
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) dec(i);
ll res = 0;
for(int i=0;i<tot;i++){
for(int j=1;j<sz(vec[prime[i]]);j++){
res = res+(vec[prime[i]][j] - vec[prime[i]][j-1])*(n-vec[prime[i]][j]+1);
}
}
cout<<res<<endl;
return 0;
}