2023牛客寒假算法基础集训营2 L-Tokitsukaze and Three Integers

solution

我们先来分析一下,我们需要寻找三个数,然后满足一定的条件,由于n=5000,n的三次方的复杂度肯定是不可取的,我们就得想办法优化常数。

1.第一次的错误尝试,使用vector<pair<int, pair<int, int>>>,第一维度存放a[i] a[j] % mod,第二维度存放i,j,然后再枚举a[i],用f[(a[i] a[j] % mod + a[i] % mod) % mod]++,来存放5000以内的i等于时的答案,最后再将f[i]减去(a[i] a[j] + a[i]和a[i] a[j] + a[j])这种情况。我们可以看出,这个方法基本和暴力没啥区别,属于脱裤子放屁了。

2.第二次尝试,我们换个思路,aiaj没办法压缩(ps.刚开始没想到压缩这个),我们就压缩a[i],我们将a[i] % mod,存放到b[i]里面,计算a[i] % mod后相同的数目,最后再将(a[i] a[j] % mod + i % mod) % mod的数目计算出来就可以了,再减去a[i] a[j] + a[i]和a[i] a[j] + a[j])这种情况。这种情况优化了一部分,但是优化程度还是不够,如果a[i] % mod,但是mod ==5000 == n那就相当于没有优化。于是我们将矛头转向优化a[i] a[j]

3.于是有了解法三,我们将b[a[i] * a[j] % mod]的数目先算出来,然后枚举f[a[i] % mod + j % mod],i属于1-n,j属于0-p -1,这样我们就可以得到答案了。

show code

#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cmath>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<fstream>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<unordered_map>

using namespace std;
#define endl '\n'
#define IOS                       \
    ios_base::sync_with_stdio(0); \
    cin.tie(0);                   \
    cout.tie(0);
typedef long long ll;
typedef pair<int,int> PII;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10;
ll a[N], f[5100], b[5100];//由于b里面存储的是次数,因此有可能会爆int,所以顺便存成ll
void solve(){
    int n, p;
    cin >> n >> p;
    int mod = p;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }
    for(int i = 1; i <= n; i++){
        for(int j = i + 1; j <= n; j++){
            b[(1ll * a[i] * a[j]) % mod]++;
            ll t1 = ((1ll * a[i] * a[j]) % mod + a[i] % mod) % mod;
            ll t2 = ((1ll * a[i] * a[j]) % mod + a[j] % mod) % mod;//减去有两个数相同的情况
            f[t1]--;
            f[t2]--;
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 0; j < p; j++){
            int t = (a[i] % mod + j % mod) % mod;
            f[t] += b[j];
        }
    }
    for(int i = 0; i < p; i++){
        cout << f[i] * 2 << " ";//因为三元组前两个数交换无所谓,所以×2,我们计算的时候不会算i,j和j,i只会算一遍
    }
    cout << endl;
}
int main(){
    // IOS;
    int t = 1;
    // cin >> t;
    while(t--){
        solve();
    }
    return 0;
}
最后修改:2023 年 02 月 02 日
如果觉得我的文章对你有用,请随意赞赏