1. 程式人生 > >2018南京區域賽 J題 Prime Game

2018南京區域賽 J題 Prime Game

J.Prime Game 題 意:給你一個含有n個元素的陣列a[i],定義mul(l,r)mul(l,r) = i=lrai\prod_{i=l}^r{ai},定義fac(i,j)=mul(l,r)fac(i,j) = mul(l,r)中不同素因數的個數。現在求i=1nj=infab(i,j)\sum_{i=1}^n\sum_{j=i}^nfab(i,j)。 資料範圍: 1<=n<=1e61<=n<=1e6

=1e6 1<=a[i]<=1e61<=a[i]<=1e6 輸入樣例:

10
99 62 10 47 53 9 83 33 15 24
10
6 7 5 5 4 9 9 1 8 12

輸出樣例:

248
134

思 路:這種計數題算貢獻,怎麼算貢獻呢?直接算有多少區間包含某一個素數的倍數。 例如,記錄一下所有2的倍數的位置,3的倍數的位置,之後算有多少個區間包含2倍數的位置,這個就是2這個素數的倍數的貢獻,然後算有多少個區間包含3這個素數的倍數的位置,這個就是3這個素數的貢獻。 例如樣例二: 2這個素數的倍數的位置有:1 5 9 10 3:1 6 7 10 5:3 4 7:2 那麼2貢獻的區間就有:(5-1)*1 + (9-5)*5 + (10-9)*9 + (10+1)*10 可以理解為:包含1不包含5的區間有多少,包含1和5不包含9的區間有多少。依次類推。 那麼最終就是答案。沒有提交過,思路應該是不會錯的。

收穫:計數題,算貢獻很重要,還要複習一下。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<queue>
#include<cmath>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<11
#define IN freopen
("input.txt","r",stdin) #define mst(x,y) memset(x,y,sizeof(x)); #define debug(x) cout<< #x <<" = "<< (x) <<endl; #define min(x,y) x>y?y:x #define max(x,y) x>y?x:y using namespace std; typedef long long ll; typedef pair<int,int> P; typedef unsigned long long ull; const int mod = 1e6+3; const int INF = 0x3f3f3f3f; const int LINF = 0x3f3f3f3f3f3f3f3f; const int maxn = 1e6+5; int n; int a[maxn]; vector<int> fac[maxn]; vector<int> res[maxn]; bool prime[maxn]; void seive() { mst(prime,true); for(int i=2; i<=maxn-1; i++) { if(!prime[i])continue; fac[i].push_back(i); for(int j=i+i; j<=maxn-1; j+=i) { prime[j] =false; fac[j].push_back(i); } } } int main() { IN; scanf("%d",&n); for(int i=1; i<=n; i++)scanf("%d",&a[i]); seive(); for(int i=1; i<=n;i++){ scanf("%d",&a[i]); for(int j=0;j<fac[a[i]].size();j++){ int temp = fac[a[i]][j]; res[temp].push_back(i); } } ll sum = 0; for(int i=2;i<=maxn-1;i++){ for(int j=0;j<(int)res[i].size()-1;j++)sum += (ll)(res[i][j+1]-res[i][j])*(res[i][j]); if(res[i].size())sum+=(ll)((ll)res[i].back()*(n + 1-res[i].back())); } printf("%lld\n",sum); return 0; }