CSP 2021 12月
一 序列查询
针对这一题的思路很简单,直接使用一个pair数组记录所在的位置和大小进行排序.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <iostream> #include <algorithm> #define N 1010 using namespace std;pair<int , int > a[N]; int main () { int n, m; scanf ("%d%d" , &n, &m); for (int i = 1 ; i <= n; i++) { scanf ("%d" , &a[i].first); a[i].second = i; } sort (a, a+n+1 ); int j = 0 ,ans = 0 ; for (int i = 0 ; i <= m - 1 ; i++) { while (a[j+1 ].first <= i&& j <= n) j++; if (j == n+1 ) j--; ans += a[j].second; } printf ("%d\n" , ans); }
二 序列查询新
这一题使用了一个估计的函数,求这个估计函数的结果和正确的结果之间的差距,我们可以使用的思路有两种,一种是二分+分块,一种是裸分块.
1. 分块
这种的思路其实很简单, 简单来说就是双指针的思想.
我们的数组A中的数据是 0 1 2 3… n- 1
B中的数据是 0 2 4 … (if r == 2)
B中的值同时也可以表示这个点的起始位置, a中的值也可以表示这个点对应的位置.
使用双指针的思想用i表示在a中的位置,j表示在b中的位置.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <iostream> #include <algorithm> using namespace std;#define N 200100 #define ll long long ll a[N], b[N], n, m, R; int main () { scanf ("%lld%lld" , &n, &m); for (int i = 1 ; i <= n; i++) scanf ("%lld" , &a[i]); a[n+1 ] = m; R = m/(n+1 ); ll ans = 0 , cnt = 0 ; for (cnt = 1 ; cnt*R < m;cnt++) b[cnt] = cnt*R; b[cnt++] = m; int i = 0 , j = 0 ; while (i < n + 1 || j < cnt - 1 ) { if (a[i] == b[j]) { ans += (min (a[i+1 ], b[j+1 ]) - a[i])* abs (i - j); i++; j++; } else if (a[i] < b[j]) { ans += (min (a[i+1 ] ,b[j]) - a[i])* abs (j - 1 - i); i++; } else { ans += (min (a[i], b[j+1 ]) - b[j])* abs (i - j - 1 ); j++; } } printf ("%lld\n" ,ans); return 0 ; }
2. 分块 + 二分
进行二分保证每次的分块的大小关系都是确定的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <bits/stdc++.h> using namespace std;long long h (long long i, long long r) { if (i < 0 ) return 0 ; else return r * ((i + 1 ) / r - 1 ) * ((i + 1 ) / r) / 2 + (i + 1 ) % r * (i / r); } long long cal (long long fi, long long lft, long long rgt, long long r) { return abs (h (rgt, r) - h (lft - 1 , r) - fi * (rgt - lft + 1 )); } int main () { long long n, N, t; cin >> n >> N; vector<long long > a = {0 }; for (int i = 0 ; i < n; ++i) { cin >> t; a.push_back (t); } a.push_back (N); long long r = N / (n + 1 ), ans = 0 ; for (long long fi = 0 ; fi <= n; ++fi) { long long lft = a[fi], rgt = a[fi + 1 ] - 1 ; if (lft / r >= fi || rgt / r <= fi) ans += cal (fi, lft, rgt, r); else ans += cal (fi, lft, r * fi, r) + cal (fi, r * fi + 1 , rgt, r); } cout << ans << endl; return 0 ; }