@topcoder - TCO19 Regional Wildcard Wildcard Round - D1L2@ Diophantine


@description@

令 p[] 为质数序列:p[0] = 2, p[1] = 3, p[2] = 5,以此类推。

令 D 为正整数常数。对于每一个 i >= 0,令 q[i] = q[i] * q[i + D]。

考虑等式 V + W + X + Y = Z。

现给定 N 与 D。统计上面等式的解的数量,同时要求 V <= W <= X <= Y 且所有量 V, W, X, Y, Z 都属于集合 Q = {q[0], q[1], ..., q[N-1]}。

Constraints
1 <= N <= 2500,0 <= D <= 2500。

Examples
0)
15
1
Returns: 2
两个解如下:
6 + 15 + 323 + 323 = 667
6 + 143 + 221 + 1147 = 1517

1)
2470
0
Returns: 0
不存在任何解。

@solution@

假如等式是这样的:W + X + Y = Z。
我们可以变为 W + X = Z - Y,然后 meet in the middle 即可。

那么 5 个变量怎么办呢?注意还有一个条件:p 是质数。
质数有一个什么性质呢?比较复杂的性质当然不是我们分析的目标。我们只考虑质数的奇偶性。

奇偶分析一波,可以发现 5 个变量不可能同时为奇数。然而质数中只有 2 为偶数,所以相当于一定存在一个 2。
而又因为 2 是最小的那个质数,所以得到 V = 2*p[D]。
然后就可以愉快地 meet in the middle 了。

@accepted code@

#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;
class Diophantine{
    #define MAXN 2500
    #define PRIME 60000
    #define HASHSIZE 1000037
    typedef long long ll;
    typedef pair<ll, int> pii;
    #define fi first
    #define se second
    private:
    int prm[PRIME + 5], nprm[PRIME + 5], pcnt;
    void sieve() {
        for(int i=2;i<=PRIME;i++) {
            if( !nprm[i] ) prm[pcnt++] = i;
            for(int j=0;i*prm[j]<=PRIME;j++) {
                nprm[i*prm[j]] = true;
                if( i % prm[j] == 0 ) break;
            }
        }
    }
    vector<pii>hsh[HASHSIZE];
    void hash_insert(ll x) {
        int y = x % HASHSIZE;
        for(int i=0;i<hsh[y].size();i++)
            if( hsh[y][i].fi == x ) {
                hsh[y][i].se++;
                return ;
            }
        hsh[y].push_back(make_pair(x, 1));
    }
    int hash_search(ll x) {
        int y = x % HASHSIZE;
        for(int i=0;i<hsh[y].size();i++)
            if( hsh[y][i].fi == x )
                return hsh[y][i].se;
        return 0;
    }
    public:
    ll q[MAXN + 5];
    int countSolutions(int N, int D) {
        sieve();
        for(int i=0;i<N;i++)
            q[i] = prm[i] * prm[i + D];
        int ans = 0;
        for(int i=N-1;i>=0;i--) {
            for(int j=i+1;j<N;j++)
                if( q[j] - q[i] - q[0] > 0 )
                    hash_insert(q[j] - q[i] - q[0]);
            for(int j=i;j>=0;j--)
                ans += hash_search(q[i] + q[j]);
        }
        return ans;
    }
};

@details@

一开始看错题了,还以为只有 4 个变量,然后就以为是 meet in the middle 的题。
结果发现是 5 个变量,然后修正一下想法就过了。

这算是。。。因祸得福吗。。。

猜你喜欢

转载自www.cnblogs.com/Tiw-Air-OAO/p/11622489.html