Gym - 101981J Prime Game 数论

 很容易想到考虑每个质因子对全局的贡献。

思路就是考虑一边。

每个质因可能因为前或后已经出现过质因子了难以计算。不妨对每个质因子采用如下策略,每个质因子的管辖范围是当前位置到前一个质因子位置这段区间,以及到最后的区间。可以想到这样的计数方法是不会重复的。

关于实现:
枚举质因子的时候注意循环条件,我一开始是prime[j] < a[i],这样最坏会遍历cnt遍。一种更好的方法是类似求因子,当然还要注意本身就是质因子的情况。

#pragma warning(disable:4996)

#include<iostream>
#include<algorithm>
#include<bitset>
#include<tuple>
#include<unordered_map>
#include<fstream>
#include<iomanip>
#include<string>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#include<list>
#include<queue>
#include<stack>
#include<sstream>
#include<cstdio>
#include<ctime>
#include<cstdlib>
#define pb push_back
#define INF 0x3f3f3f3f
#define inf 0x7FFFFFFF
#define moD 1000000003
#define pii pair<ll,ll>
#define eps 1e-8
#define equals(a,b) (fabs(a-b)<eps)
#define bug puts("bug")
#define re  register
#define fi first
#define se second
typedef  long long ll;
typedef unsigned long long ull;
const ll MOD = 1e6 + 7;
const int maxn = 1e6 +5;
const double Inf = 10000.0;
const double PI = acos(-1.0);
using namespace std;

int prime[maxn];   
int vis[maxn];     
int lastpos[maxn];
ll a[maxn];

int euler_sieve(int n) {
    int cnt = 0;
    for (int i = 2; i <= n; i++) {
        if (!vis[i]) prime[cnt++] = i;
        for (int j = 0; j < cnt; j++) {
            if (i * prime[j] > n) break;
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0) break;
        }
    }
    return cnt; 
}


int readint() {
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}

int readll() {
    ll x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}


void Put(ll x)   //输出 
{
    if (x > 9) Put(x / 10);
    putchar(x % 10 + '0');
}


int main() {
    memset(lastpos, -1, sizeof lastpos);
    int cnt = euler_sieve(maxn);
    int n;
    ll res = 0;
    n = readint();
    for (int i = 0; i < n; i++) a[i] = readll();
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < cnt && (ll)prime[j] * prime[j] <= a[i]; j++) {
            if (a[i] % prime[j] == 0) { 
                if (lastpos[prime[j]] == -1) res += (ll)(1 + i) * (n - i);
                else res += (ll)(i - lastpos[prime[j]]) * (n - i);
                lastpos[prime[j]] = i;
            }
            while (a[i] % prime[j] == 0) a[i] /= prime[j];
        }
        if (a[i] > 1) if (lastpos[a[i]] == -1) res += (ll)(1 + i) * (n - i), lastpos[a[i]] = i;  else res += (ll)(n - i) * (i - lastpos[a[i]]), lastpos[a[i]] = i;
    }
    Put(res);
}

猜你喜欢

转载自www.cnblogs.com/hznumqf/p/13394269.html