0724 考试记录
总结:
- 多打暴力,不费时间并且对分数非常有用
- 交之前检查一遍代码,包括静态查错以及 记得关掉注释!!! (本场比赛因此爆零)
- 对于以上,建议保证在写下一道题的时候反复检查上一道的代码为成品
以下是考试题目分析&总结:
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;
}
标签:10,0724,记录,int,复杂度,long,MAXN,考试,MOD
From: https://www.cnblogs.com/wwzzhhone/p/18320740