Codeforces Round #727 (Div. 2) 题解
文章目錄
- A. Contest Start
- B. Love Song
- C. Stable Groups
- D. PriceFixed
- E. Game with Cards
- F. Strange Array
#727-Div.2
A. Contest Start
數學題,分類討論
- 一般的,一段區間[l,r][l,r][l,r]會對后面固定人數造成影響,假設是kkk
- 最后kkk個人,因為自己后面的人數不夠kkk,所以貢獻總和是k×(k?1)2\frac{k\times(k-1)}{2}2k×(k?1)?
顯然固定人數為tx\frac{t}{x}xt?
#include <cstdio> #define int long long int T, n, x, t;signed main() {scanf( "%lld", &T );while( T -- ) {scanf( "%lld %lld %lld", &n, &x, &t );int k = t / x;if( n < k ) printf( "%lld\n", n * ( n - 1 ) / 2 );else printf( "%lld\n", ( n - k ) * k + ( k - 1 ) * k / 2 );}return 0; }B. Love Song
前綴和統計[l,r][l,r][l,r]區間內每個字符的個數×\times×字符在字母表的排位
#include <cstdio> #define maxn 100005 int n, Q; char s[maxn]; int cnt[maxn][26];int main() {scanf( "%d %d %s", &n, &Q, s + 1 );for( int i = 1;i <= n;i ++ ) {for( int j = 0;j < 26;j ++ )cnt[i][j] = cnt[i - 1][j];cnt[i][s[i] - 'a'] ++;}while( Q -- ) {int l, r;scanf( "%d %d", &l, &r );int ans = 0;for( int i = 0;i < 26;i ++ )ans += ( i + 1 ) * ( cnt[r][i] - cnt[l - 1][i] );printf( "%d\n", ans );}return 0; }C. Stable Groups
貪心。
排個序,把能放在一起的放在一起,然后記錄相鄰組之間需要的“橋”的個數,用優先隊列存儲
顯然,需要越少越先滿足,留下更多的kkk滿足后面
#include <queue> #include <cstdio> #include <algorithm> using namespace std; #define int long long #define maxn 200005 priority_queue < int, vector < int >, greater < int > > q; int n, k, x; int a[maxn];signed main() {scanf( "%lld %lld %lld", &n, &k, &x );for( int i = 1;i <= n;i ++ )scanf( "%lld", &a[i] );sort( a + 1, a + n + 1 );int cnt = 1;for( int i = 1;i < n;i ++ )if( a[i + 1] - a[i] > x ) {cnt ++;q.push( ( a[i + 1] - a[i] - 1 ) / x );}while( ! q.empty() ) {if( q.top() <= k ) k -= q.top(), cnt --, q.pop();else break;}printf( "%lld\n", cnt );return 0; }D. PriceFixed
貪心模擬,按bbb排序
用最難滿足的購買盡可能觸碰易滿足的bbb
#include <cstdio> #include <algorithm> using namespace std; #define int long long #define maxn 100005 struct node {int a, b; }it[maxn]; int n;bool cmp( node x, node y ) {return x.b > y.b; }signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ )scanf( "%lld %lld", &it[i].a, &it[i].b );sort( it + 1, it + n + 1, cmp );int tot = 0, ans = 0;for( int i = 1;i <= n;i ++ ) {if( tot >= it[n].b ) {ans += it[n].a;tot += it[n].a;it[n].a = 0;i --;n --;}else if( tot + it[i].a < it[n].b ) {tot += it[i].a;ans += ( it[i].a << 1 );it[i].a = 0;} else {int t = it[n].b - tot;it[i].a -= t;ans += ( t << 1 );tot += t;ans += it[n].a;tot += it[n].a;it[n].a = 0;n --;i --;}}if( ! it[n].a )printf( "%lld\n", ans );else {if( tot >= it[n].b )printf( "%lld\n", ans + it[n].a );else if( it[n].a + tot <= it[n].b )printf( "%lld\n", ans + ( it[n].a << 1 ) );else {int t = it[n].b - tot;ans += ( t << 1 );it[n].a -= t;ans += it[n].a;printf( "%lld\n", ans );}}return 0; }E. Game with Cards
設Li,j:L_{i,j}:Li,j?: 左手為第iii個數,右手為第jjj個數,i<ji<ji<j,是否合法
Ri,j:R_{i,j}:Ri,j?: 右手為第iii個數,左手為第jjj個數,i<ji<ji<j,是否合法
顯然有暴力的n2n^2n2轉移
Li,j=[ai∈[al,j,ar,j?aj∈[bl,j,br,j]]={Li,j?1i≠j?1∑k=1j?2Rk,j?1i=j?1Ri,j=[ai∈[bl,j,br,j?aj∈[al,j,ar,j]]={Ri,j?1i≠j?1∑k=1j?2Lk,j?1i=j?1L_{i,j}=\bigg[a_i\in [a_{l,j},a_{r,j}\bigcap a_j\in[b_{l,j},b_{r,j}]\bigg]=\begin{cases}L_{i,j-1}&&&&&i≠j-1\\\sum_{k=1}^{j-2}R_{k,j-1}&&&&&i=j-1\end{cases}\\R_{i,j}=\bigg[a_i\in [b_{l,j},b_{r,j}\bigcap a_j\in[a_{l,j},a_{r,j}]\bigg]=\begin{cases}R_{i,j-1}&&&&&i≠j-1\\\sum_{k=1}^{j-2}L_{k,j-1}&&&&&i=j-1\end{cases}\\ Li,j?=[ai?∈[al,j?,ar,j??aj?∈[bl,j?,br,j?]]={Li,j?1?∑k=1j?2?Rk,j?1??????i?=j?1i=j?1?Ri,j?=[ai?∈[bl,j?,br,j??aj?∈[al,j?,ar,j?]]={Ri,j?1?∑k=1j?2?Lk,j?1??????i?=j?1i=j?1?
顯然是可以用線段樹維護成logloglog的
F. Strange Array
連著兩題線段樹好,很好!
定義S1:[l,r]S_1:[l,r]S1?:[l,r] 中小于aia_iai?的個數,S2:[l,r]S_2:[l,r]S2?:[l,r] 中等于aia_iai?的個數,S3:[l,r]S_3:[l,r]S3?:[l,r] 中大于aia_iai?的個數
顯然位置iii的奇怪度為
max?{S1+S2??S1+S3+S2+12??S1+S3+S2+12??(S1+1)\max\begin{cases} S_1+S_2-\lceil\frac{S_1+S_3+S_2+1}{2}\rceil\\ \lceil\frac{S_1+S_3+S_2+1}{2}\rceil-(S_1+1) \end{cases} max{S1?+S2???2S1?+S3?+S2?+1???2S1?+S3?+S2?+1???(S1?+1)?
發現:同時在比aia_iai?大和比aia_iai?小的數中扔掉若干個相同的數,答案并不會發生變化
如此說來有用的只有二者的差,S1S2S3
如果aia_iai?放在S2S_2S2?的第一位,我們則非常希望max{S3},min{S1}max\{S_3\},min\{S_1\}max{S3?},min{S1?}這樣中位數才會遠離S2S_2S2?的第一位
如果aia_iai?放在S2S_2S2?的倒數第一位,我們則非常希望min{S3},max{S1}min\{S_3\},max\{S_1\}min{S3?},max{S1?}
顯然可以線段樹維護查詢了,將小于等于aia_iai?的標記為?1-1?1
對于若干個相同的aia_iai?位置,先查再改是一種情況,改了再查是另一種情況
#include <cstdio> #include <vector> #include <iostream> #include <algorithm> using namespace std; #define maxn 200005 struct node {int maxx, minn, lazy; }t[maxn << 2]; vector < int > s[maxn]; int n; int ans[maxn];void pushdown( int num ) {t[num << 1].maxx += t[num].lazy;t[num << 1].minn += t[num].lazy;t[num << 1].lazy += t[num].lazy;t[num << 1 | 1].maxx += t[num].lazy;t[num << 1 | 1].minn += t[num].lazy;t[num << 1 | 1].lazy += t[num].lazy;t[num].lazy = 0; }void modify( int num, int l, int r, int L, int R, int val ) {if( L <= l && r <= R ) {t[num].lazy += val;t[num].maxx += val;t[num].minn += val;return;}pushdown( num );int mid = ( l + r ) >> 1;if( L <= mid ) modify( num << 1, l, mid, L, R, val );if( mid < R ) modify( num << 1 | 1, mid + 1, r, L, R, val );t[num].maxx = max( t[num << 1].maxx, t[num << 1 | 1].maxx );t[num].minn = min( t[num << 1].minn, t[num << 1 | 1].minn ); }int query_max( int num, int l, int r, int L, int R ) {if( L > R ) return 0; if( R < l || r < L ) return -1e9;if( L <= l && r <= R ) return t[num].maxx;pushdown( num );int mid = ( l + r ) >> 1;return max( query_max( num << 1, l, mid, L, R ), query_max( num << 1 | 1, mid + 1, r, L, R ) ); }int query_min( int num, int l, int r, int L, int R ) {if( L > R ) return 0;if( R < l || r < L ) return 1e9;if( L <= l && r <= R ) return t[num].minn;pushdown( num );int mid = ( l + r ) >> 1;return min( query_min( num << 1, l, mid, L, R ), query_min( num << 1 | 1, mid + 1, r, L, R ) ); }int main() {scanf( "%d", &n );for( int i = 1, x;i <= n;i ++ ) {scanf( "%d", &x );s[x].push_back( i );modify( 1, 1, n, i, n, -1 );}for( int i = 1;i <= n;i ++ ) {for( int j = 0;j < s[i].size();j ++ ) {//放在眾多相同的最后一個->后面的盡量少前面的盡量多 int k = s[i][j];int l = max( 0, query_max( 1, 1, n, 1, k - 1 ) );//compare with 0 means just choosing k itselfint r = query_min( 1, 1, n, k, n );ans[k] = max( ans[k], ( l - r + 2 ) / 2 - 1 );}for( int j = 0;j < s[i].size();j ++ )modify( 1, 1, n, s[i][j], n, 2 );//抵消掉之前i對[i,n]造成的-1影響 然后再變成1后的影響 所以一次性加2 for( int j = 0;j < s[i].size();j ++ ) {//放在眾多相同的第一個->后面的盡量多前面的盡量少 int k = s[i][j];int l = min( 0, query_min( 1, 1, n, 1, k - 1 ) );int r = query_max( 1, 1, n, k, n );ans[k] = max( ans[k], ( r - l ) - ( r - l + 2 ) / 2 );}}for( int i = 1;i <= n;i ++ )printf( "%d ", ans[i] );return 0; }總結
以上是生活随笔為你收集整理的Codeforces Round #727 (Div. 2) 题解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ #3166. [Heoi201
- 下一篇: 修改应用程序热键_如何通过热键组合在OS