UVALive - 8478 (计蒜客) Sum of the Line 推导+普通容斥

题意:

题目给定了 T(r,c) 和 S(r,c) 的定义; 

现在要求 sigma ( S(r,i)  ) : i in range(1,n);  ①

思路:

对于S(n,c) 我们可以理解成从 c 到 n 之间跟 n 互质的数的和;那么 ①式 可以理解为:sigma(k²) : k 与 n 互质

那么我们可以求 所有1-n的数的平方和 然后减去 跟n不互质的数的平方和(即跟n有共同的质因子)

两个部分都可以O(n)的得到解答,第二部分要求的就是n的素因子的倍数的平方和

但是第二部分会产生重复的,很明显这是一个普通的容斥,而且n的不同的素因子不会超过9个,所以我们可以用O(2^9) 枚举n的所有质因子组合的情况,奇数个加,偶数个减;

对于k的平方和求解即: (k^2 + (2*k)^2 + ... + (t*k)^2) = k^2 * (1^2 + 2^2 + .. + t^2);

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <map>
#include <queue>
#include <vector>

using namespace std;
typedef long long ll;
const int maxn = 1e4 + 7;
const int maxd = 1e8+10;
const ll mod = 998244353;

bool vis[maxn];
vector<ll> prim;
vector<int> p;
ll inv6;


void work(ll n) {
  p.clear();
  ll m = n;
  for(int i = 2; i*i <= n; ++i) {
    if(m % i == 0) {
      p.push_back(i);
      while(m%i == 0) m /= i;
    }
  }
  if(m != 1) p.push_back(m);
}

ll ans(ll n) {
  ll res = 0;
  int m = p.size();
  m = (1<<m);
  for(int i = 1; i < m; ++i) {
    int cnt = 0, t = 1;
    ll num = 1LL;
    for(int j = 0; j < p.size(); ++j) {
      if(i&t) {
        num *= p[j];
        cnt++;
      }
      t <<= 1;
    }
    if(cnt&1) {
      ll tt = n / num;
      res = ( res + (num*num%mod)*(tt*(tt+1)%mod*(2*tt+1)%mod*inv6%mod)%mod )%mod;
    } else {
      ll tt = n / num;
      res = ( res - (num*num%mod)*(tt*(tt+1)%mod*(2*tt+1)%mod*inv6%mod)%mod + mod )%mod;
    }
  }
  return res;
}
ll pow_(ll a, ll n) {
  ll res = 1;
  while(n) {
    if(n&1)
      res = (res * a) % mod;
    a = (a * a) % mod;
    n >>= 1;
  }
  return res;
}
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0); cout.tie(0);
  
  inv6 = pow_(6LL,mod-2);
  int T;
  cin >> T;
  while(T--) {
    ll n;
    cin >> n;
    work(n);
    ll sum = ((n)*(n+1)%mod*(2*n+1)%mod*inv6)%mod;
    sum = (sum - ans(n) + mod) % mod;
    cout << sum << endl;
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/xiang_6/article/details/81623952