ferinの競プロ帳

競プロについてのメモ

2016-2017 ACM-ICPC Asia-Bangkok Regional Contest C - Big Bang

問題ページ
時刻 t に座標 (x,y,z) にいる粒子は,時刻 kt に座標 (kx,ky,kz) に存在する.よって,(x/d,y/d,z/d,t/d) d=\gcd(x,y,z,t) が同じ場合,同じ粒子であると判定できる.\gcd(x,y,z,t)=1, 1 \leq x,y,z,t \leq N であるような4数が何通り存在するか求める問題に帰着できた.

これは約数系包除で解ける.gcdがi以上であるような4数の組は \lfloor N/i \rfloor^4 個で簡単に求められる.dp[i] = \lfloor N/i \rfloor^4 - sum(dp[iの倍数]) をiが大きい方から順に求める.

80000はllでもオーバーフローするので多倍長が必要になる.手元でint128で1ケースだけ計算すると答えがわかるのでこのパターンだけ埋め込む.

#include <bits/stdc++.h>  
using namespace std;  
using ll = long long;  
using PII = pair<ll, ll>;  
#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)  
#define REP(i, n) FOR(i, 0, n)  
#define ALL(x) x.begin(), x.end()  
template<typename T> void chmin(T &a, const T &b) { a = min(a, b); }  
template<typename T> void chmax(T &a, const T &b) { a = max(a, b); }  
struct FastIO {FastIO() { cin.tie(0); ios::sync_with_stdio(0); }}fastiofastio;  
#ifdef DEBUG_   
#include "../program_contest_library/memo/dump.hpp"  
#else  
#define dump(...)  
#endif  
const ll INF = 1LL<<60;  
  
// using int128 = __int128_t;  
// using uint128 = __uint128_t;  
// ostream &operator<<(ostream &os, int128 value) {  
//     ostream::sentry s(os);  
//     if (s) {  
//         uint128 tmp = value < 0 ? -value : value;  
//         char buffer[128];  
//         char *d = end(buffer);  
//         do {  
//             --d;  
//             *d = "0123456789"[tmp % 10];  
//             tmp /= 10;  
//         } while (tmp != 0);  
//         if (value < 0) --d, *d = '-';  
//         int len = end(buffer) - d;  
//         if (os.rdbuf()->sputn(d, len) != len) {  
//             os.setstate(ios_base::badbit);  
//         }  
//     }  
//     return os;  
// }  
// istream &operator>>(istream &is, int128 &val) {  
//     string s; is >> s;  
//     val = 0;  
//     REP(i, s.size()) if ('0' <= s[i] && s[i] <= '9') {  
//         val = 10 * val + s[i] - '0';  
//     }  
//     return is;  
// }  
  
void solve() {  
    ll n;  
    cin >> n;  
  
    vector<ll> dp(n+1);  
    for(ll i=n; i>=1; --i) {  
        // gcdがiとなるw,x,y,zが何通り?  
        const ll tmp = n/i;  
        dp[i] = tmp*tmp*tmp*tmp;  
        for(ll j=2*i; j<=n; j+=i) {  
            dp[i] -= dp[j];  
        }  
    }  
  
    cout << dp[1] << endl;  
}  
  
int main(void) {  
    REP(i, 4) solve();  
    cout << "37844569649859454367" << endl;  
  
    return 0;  
}