Gym 101981J - Prime Game[2018-2019 ACM-ICPC Asia Nanjing Regional Contest Problem J]

题目链接:http://codeforces.com/gym/101981/attachments

题解:

考虑每个质因子对于整体答案的贡献。

拿第二组样例算一算就不难发现:第 p 个位置上的数,其包含的任意一个素因子,它原本应当产生的贡献有 (np+1)p(n−p+1)⋅p,

但是考虑到若其前面出现过一样的素数,那么应当减去一些重复计算的区间。假设它前面的和它一样的素数,最后一次出现在 q 位置,那么就应当减去 (n−p+1)⋅q,即 a[p]a[p] 包含的任意一个质因子其产生的贡献为 (np+1)p(np+1)q=(np+1)(pq)。

不妨用 pos[i][k]pos[i][k] 来存储每个素因子的 “pp”,pos[i][k1]pos[i][k−1] 存储每个素因子的 “qq”。换句话说,pos[i][k]pos[i][k] 代表某个素因子 ii 在 a[1n]a[1∼n] 中第 kk 次“出现”的位置是 pos[i][k]pos[i][k];特别地,令 pos[i][0]=0pos[i][0]=0。那么对于任意素因子 ii,它对答案的贡献是 (npos[i][k]+1)(pos[i][k]pos[i][k1])(n−pos[i][k]+1)⋅(pos[i][k]−pos[i][k−1])。

我们可以对 a[1n]a[1∼n] 分解质因数,然后更新相应的 pos[i][k]pos[i][k]。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+5;
int n,t,a[maxn];
vector<int> pos[maxn];
int prime[maxn],check[maxn];
void LinePrime() {
    t = 0;
    for(int i=2; i<maxn; i++) {
        if(check[i]==0) prime[t++] = i;
        for(int j=0; j<t; j++) {
            if(i*prime[j]>maxn) break;
            check[i*prime[j]] = 1;
            if(i%prime[j]==0) break;
        }
    }
}
void dec(int p) {
    int num = a[p];
    for(int i=0; i<t&&prime[i]*prime[i]<=num; i++) {
        if(num%prime[i]==0)  pos[prime[i]].push_back(p);
        while(num%prime[i]==0) num /= prime[i];
    }
    if(num>1) pos[num].push_back(p);
}
void init(){
    LinePrime();
    for(int i=0; i<t; i++){
        pos[prime[i]].push_back(0);
    } 
      
}
int  main() {
    ll ans = 0;
    init();
    cin>>n;
    for(int i=1; i<=n; i++) {
        cin>>a[i];
        dec(i);
    }
    for(int i=0;i<t;i++){
        for(int j=1;j<pos[prime[i]].size();j++){
            ans+=(ll)(n-pos[prime[i]][j]+1)*(pos[prime[i]][j]-pos[prime[i]][j-1]);
        }
    }
    cout<<ans<<endl;
    return 0;
}
View Code

然而,我的逻辑是 考虑若其后面出现一样的素数,就减去重复计算的区间。假设它后面的和它一样的素数,最近一次出现在 q 位置,那么就应当减去 (n−q+1)⋅p

即 a[p]a[p] 包含的任意一个质因子其产生的贡献为 (np+1)p(n−q+1)⋅p=p(q-p),但是答案总是小于正确答案。。。

错误代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+5;
int n,t,a[maxn];
vector<int> pos[maxn];
int prime[maxn],check[maxn];
void LinePrime() {
    t = 0;
    for(int i=2; i<maxn; i++) {
        if(check[i]==0) prime[t++] = i;
        for(int j=0; j<t; j++) {
            if(i*prime[j]>maxn) break;
            check[i*prime[j]] = 1;
            if(i%prime[j]==0) break;
        }
    }
}
void dec(int p) {
    int num = a[p];
    for(int i=0; i<t&&prime[i]*prime[i]<=num; i++) {
        if(num%prime[i]==0)  pos[prime[i]].push_back(p);
        while(num%prime[i]==0) num /= prime[i];
    }
    if(num>1) pos[num].push_back(p);
}
void init() {
    LinePrime();
    for(int i=0; i<t; i++) {
        pos[prime[i]].push_back(0);
    }

}
int  main() {
    ll ans = 0;
    init();
    cin>>n;
    for(int i=1; i<=n; i++) {
        cin>>a[i];
        dec(i);
    }

    for(int i=0; i<20; i++) {
        if(pos[prime[i]].size()==2){
            ans += (ll)(n-pos[prime[i]][1]+1)*pos[prime[i]][1]; 
        } 
        for(int j=1; j<pos[prime[i]].size()-1; j++) {
            cout<<"Prime="<<prime[i]<<endl;
            cout<<"q="<<pos[prime[i]][j]<<endl;
            cout<<"p="<<pos[prime[i]][j+1]<<endl;
            cout<<"P-q="<<pos[prime[i]][j+1]-pos[prime[i]][j]<<endl;
            ans+=(ll)pos[prime[i]][j]*(pos[prime[i]][j+1]-pos[prime[i]][j]);
        }
    }
    cout<<ans<<endl;
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Lemon1234/p/11625015.html