Dashboard - Codeforces Round 904 (Div. 2) - Codeforces
C. Medium Design 题意 给长度为m的数组a,初始均为0。$1\le m \le 10^9$
给出一些区间,请你选出其中某些区间。每选择一个区间,就令区间中的数都加一,问 数组中最大值$max(a)$ ,和最小值$ min(a)$ 的差,最大为多少。
思路 考虑以下贪心策略:如果我们确定了最终第$i$个数是最大的那个数,即$ a[i] = max(a)$ , 那么我们就可以选择所有的包含$i$的区间。然后摒弃所有不包含$i$的区间。(选上包含$i$的区间一定会令$max(a)++$) , 这样我们可以遍历所有的数组下标$i$。 计算假使$i$为最大数时的$ans$,最终选择最大的$ans$即可。
我们可以先对区间进行排序。 然后根据右端点从小到大维护优先队列$pq$。这样按顺序遍历区间数组,就可以引入所有左端点小于等于$ i $的区间。然后通过剔除优先队列中的右端点小于i的区间。 这样优先队列中就保存了所有的包含$i$的区间。 因此有 $max(a) = pq.size()$ ,
再考虑寻找最小值$min(a)$ , 如果我们使用 $cntl$ 左端点为1的区间的数量。同理使用 $cntr$记录右端点为$m$的区间的数量 。那么 $min(a) = min(cntl,cntr)$ 。
本题m较大。需要离散化处理。
代码 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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <bits/stdc++.h> using namespace std;typedef pair<int ,int > PII;struct cmp { bool operator () (PII x,PII y) {return x.second > y.second;} }; int main () { int t; cin>>t; cin.tie (0 );cout.tie (0 ); while (t--){ int n,m; cin>>n>>m; vector<int > vec (2 * n+5 ) ; vector<PII> seq (2 *n+5 ) ; int l ,r; for (int i = 1 ;i<=n;i++){ cin>>l>>r; seq[i] = make_pair (l,r); vec[2 * i - 1 ] = l; vec[2 * i] = r; } vec[0 ] = 1 ; vec[2 * n + 1 ] = m; sort (vec.begin (),vec.begin ()+2 +2 *n); int len = unique (vec.begin (),vec.begin ()+2 +2 *n) - vec.begin (); unordered_map<int ,int > mp; for (int i = 0 ;i<len;i++){ mp[vec[i]] = i; } sort (seq.begin () + 1 ,seq.begin ()+1 +n); int ans = -1 ; int cntl = 0 ,cntr = 0 ; priority_queue<PII , vector<PII> ,cmp> pq; int p = 1 ; for (int i = 0 ;i<len;i++){ while (p<=n && seq[p].first <= vec[i]){ if (seq[p].first == 1 ) cntl ++; if (seq[p].second == m) cntr ++; pq.push (seq[p]); p++; } while (pq.size () && pq.top ().second < vec[i]){ PII temp = pq.top (); if (temp.first == 1 ) cntl--; pq.pop (); } ans = max (ans,(int )pq.size () - min (cntl,cntr)); } cout<<ans<<endl; } return 0 ; }
D. Counting Rhyme 题意 给出有n个数的数组a,问有多少个$(i,j)$ 对($(i,j)$与$(j,i)$ 视为同一个对),满足 不存在 任何k,使得$a_k $是$ a_i,a_j$ 的公因子。
($1 \le n \le 10^6, 1 \le a_i \le n$)
思路 dp,设$dp[i] $ 为以$i$为最大公因子的对有多少个。我们可以统计 有多少个数有i这个因子
, 假设有cc个数,那么就会有$\frac{cc (cc - 1)}{2}$ 个以 $i$为公因子 (不是最大公因子)的对。 我们要求最大公因子,就还需要令$ dp[i] = dp[i] - \sum _{t = 2} ^{i t <= n} {dp[t * i]}$ 。(即减去以$i$的倍数为最大公因子的对的数量)。
所以最终的$dp$状态转移方程为$ dp[i] = \frac{cc (cc - 1)}{2}- \sum _{t = 2} ^{i t <= n} {dp[t * i]}$ 。 同时注意,应该从n开始,逐渐转移到1 。
最后,我们需要求 不存在 任何k,使得$a_k $是$ a_i,a_j$ 的公因子。 因此需要标记a数组中所有的数以及他们的倍数 ,最后不被标记的dp值的总和就是答案。
代码 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 34 35 36 37 38 #include <bits/stdc++.h> using namespace std;#define int long long signed main () { int t; cin>>t; while (t--){ int n; cin>>n; vector<int > cnt (n+5 ) ; vector<int > dp (n+5 ) ; vector<bool > vis (n+5 ) ; for (int i = 1 ;i<=n;i++){ int num; scanf ("%d" ,&num); vis[num] = 1 ; cnt[num]++; } for (int i = n;i>=1 ;i--){ int p = i * 2 ; int cc = cnt[i]; while (p <= n){ if (cnt[i]) vis[p] = 1 ; cc += cnt[p]; dp[i] -= dp[p]; p += i; } dp[i] += cc * (cc - 1 ) / 2 ; } int ans = 0 ; for (int i = 1 ;i<=n;i++){ if (!vis[i]) ans += dp[i]; } cout<<ans<<endl; } return 0 ; }