0724 考试记录

0724 考试记录

总结:

  1. 多打暴力,不费时间并且对分数非常有用
  2. 交之前检查一遍代码,包括静态查错以及 记得关掉注释!!! (本场比赛因此爆零)
  3. 对于以上,建议保证在写下一道题的时候反复检查上一道的代码为成品

以下是考试题目分析&总结:

T1

题意简述:

给你一个序列 $ l $ 与正整数 \(T\) , 求出满足条件\(\lfloor \frac{l_a} {l_b} \rfloor + \lfloor \frac{l_c}{l_d} \rfloor = T\) 的四元组\((a, b, c, d)\)数量

$ 1≤n≤10^6 ,,, 0≤T ≤10^6 ,,, 1≤ l_i ≤10^6 $

思路:

首先一个非常显然的思路是我们去枚举 \(a, b\) , 然后组合计数即可

但是这样的复杂度我们显然是不能接受的

我们考虑优化. 不难发现我们可以用桶+前缀和来快速求得某一连续区间的数的数量, 结合整数分块, 我们可以做到\(O(n \sqrt n)\)的复杂度. 这个复杂度我们可以做到80pts

我们考虑进一步优化. 在这个算法中有三个求解量: \(s_a \,\,\,s_b\,\,\,\lfloor\frac{s_a}{s_b}\rfloor\) 我们刚刚相当于枚举了\(s_a \,\,\,s_b\) 然后进行了优化.我们此时可以考虑枚举\(s_b {和} \lfloor\frac{s_a}{s_b}\rfloor\)看看复杂度能否获得提升

我们不难发现对于一个固定的\(s_b\)和商, 其对应的\(s_a\)范围非常好找, 即\([s_b * i, s_b * i + s_ b- 1]\)

对于一个固定的\(s_b\), 其能做出的贡献次数为 \(\frac{n}{s_b}\) 根据调和级数, 总和为\(\log n\)级别 至此, 我们完成了复杂度的优化, AC本题.

\(n \sqrt n\)做法
#include<bits/stdc++.h>
using namespace std;

const int MAXN = 1e6 + 10, MOD = 998244353;
int n, T;
int l[MAXN];
long long t[MAXN];
long long ans[MAXN];

long long sum = 0;

vector <pair<int, int> > pir[MAXN];

inline void ad(long long &to, long long a){
    to = (to + a) % MOD;
}

int main(){

    freopen("floor.in","r",stdin);
    freopen("floor.out","w", stdout);

    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);

    cin >> n >> T;

    for(int i = 1; i <= n; i++){
        cin >> l[i]; t[l[i]] ++;
    }   

    for(int i = 1; i <= 1e6; i++) t[i] += t[i - 1];

    // for(int i = 1; i <= 10; i++) cout << t[i] << " ";
    // cout << "\n";

    for(int i = 1; i <= 1e6; i++){
        if(t[i] == t[i - 1]) continue;

        // cout << "getin " << i << "\n";
        int nownum = t[i] - t[i - 1];

        // ad(ans[l], 1ll * nownum * nownum);

        double sq = sqrt(i); int last = 1;

        for(int j = 1; j <= sq; j++){
            // cout << "first part of " << i << " with " << j << "\n";
            ans[i / j] = (ans[i / j] + 1ll * nownum * (t[j] - t[j - 1])) % MOD;
            last = j + 1;
        }


        // cout << last << "\n";

        for(int j = last - 1; j >= 1 && last <= i; j--){
            // cout << "second part of " << i << " with " << j << "\n";
            int nex = i / j;
            ans[j] = (ans[j] + 1ll * nownum * (t[nex] - t[last - 1])) % MOD;
            last = nex + 1;

            // cout << ans[j] << "\n";
        }

        ans[0] += nownum * (t[(int)1e6] - t[i]);
    }
    // cout << "\n";
//    for(int i = 0; i <= 100; i++) cout << ans[i] << "\n";
//     cout << "\n";
    for(int i = 0; i <= T; i++) ad(sum, 1ll * ans[i] * ans[T - i]);

    cout << sum;
    return 0;
}

100pts做法

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 2e6 + 10, MOD = 998244353;
int n, T;
int l[MAXN];
long long t[MAXN];
long long ans[MAXN];

long long sum = 0;

vector <pair<int, int> > pir[MAXN];

inline void ad(long long &to, long long a){
	a %= MOD;
    to = (to + a) % MOD;
}

int main(){

    freopen("floor.in","r",stdin);
    freopen("floor.out","w", stdout);

    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);

    cin >> n >> T;

    for(int i = 1; i <= n; i++){
        cin >> l[i]; t[l[i]] ++;
    }   

    for(int i = 1; i <= 2e6; i++) t[i] += t[i - 1];

    for(int i = 1; i <= 1e6; i++){
        if(t[i] == t[i - 1]) continue;
        
        long long nownum = t[i] - t[i - 1];

        for(int j = 1; j * i <= 1e6; j++){
			ans[j] += 1ll * nownum * ((t[i * (j + 1) - 1] - t[i * j - 1]) % MOD);
			ans[j] %= MOD; 
		}
		
		ans[0] += t[i - 1] * nownum;
		ans[0] %= MOD;
    }
    
    for(int i = 0; i <= T; i++) ad(sum, 1ll * ans[i] * ans[T - i]);

    cout << sum;
}
posted on 2024-07-24 13:48  Wzhone_启动  阅读(27)  评论(0)    收藏  举报