【codeforces】Codeforces Round #283 (Div. 2) 【题解】
2014-12-19 18:47
513 查看
传送门:【codeforces】Codeforces Round #283 (Div. 2)
496A. Minimum Difficulty
嘛,枚举删除,然后照着题意模拟就好。
496B. Secret Combination
同暴力枚举就好= =。
其实注意到枚举每一位作为开头时,开头的数变成0一定是以这个位置开头最佳的(我没这样写= =,直接暴力了)。
496C. Removing Columns
贪心,不断减少判断的行,同时将矛盾的列删除。
496D. Tennis Game
枚举T,然后每次走让一个人恰好赢的步数,由于我保存的是a[i] = x,即第i个位置编号为1的赢了第x小局,对编号2同理。然后每次就二分走一局需要的步数。。。最后将保存的答案按题意排序输出就好。
事实上,可以不需要二分的,只要保存a[x] = i,即编号为1的赢了第x小局时在位置i,同时预处理出每个1往回走遇到的第一个2的位置,对编号2同理。然后每次只要走t步就好了,不需要二分了。。。。
剩下的就是一些分类讨论模拟了,不细说了。
496E. Distributing Parts
这题呢,首先我们将两种区间都记录下来,按照左端点从大到小排个序,然后我们对于一个节目,将所有左端点大于等于这个节目左端点的人的右端点以及信息作为关键字插入到set,然后我们在set里面查找右端点小于等于节目右端点的最大的一个人,这个人标记为参加这个节目。每次我们都这么操作,只要最后看一下是否还有人没插入set或者set内还有元素,那么就无解,否则输出解。
这样的贪心为什么可以呢?因为假如我们每次按照上述方法选择,那么下一个节目区间的左端点一定小于等于这个节目的左端点,如果下一个节目的右端点大于等于这个节目的右端点,那么显然这样的分配是没问题的,如果下一个节目的右端点是小于这个节目的右端点的,那么我们便把下一个节目无法覆盖的位置覆盖了,保证没有漏掉,如果我们此时不是选择右端点小于等于节目右端点的最大的一个人,那么当下一个节目的右端点小于这一个节目的右端点时,便可能少覆盖了一个人,从而导致无解。大概就是这样=。=
496A. Minimum Difficulty
嘛,枚举删除,然后照着题意模拟就好。
#include <cstdio> #include <vector> #include <cstring> #include <algorithm> using namespace std ; typedef long long LL ; #define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i ) #define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i ) #define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i ) #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 1005 ; int n ; int a[MAXN] ; void solve () { int ans = MAXN ; For ( i , 1 , n ) scanf ( "%d" , &a[i] ) ; For ( i , 2 , n - 1 ) { int tmp = 0 ; For ( j , 1 , i - 2 ) tmp = max ( tmp , a[j + 1] - a[j] ) ; rep ( j , i + 1 , n ) tmp = max ( tmp , a[j + 1] - a[j] ) ; tmp = max ( tmp , a[i + 1] - a[i - 1] ) ; ans = min ( tmp , ans ) ; } printf ( "%d\n" , ans ) ; } int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; }
496B. Secret Combination
同暴力枚举就好= =。
其实注意到枚举每一位作为开头时,开头的数变成0一定是以这个位置开头最佳的(我没这样写= =,直接暴力了)。
#include <cstdio> #include <vector> #include <cstring> #include <algorithm> using namespace std ; typedef long long LL ; #define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i ) #define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i ) #define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i ) #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 1005 ; int n ; int a[MAXN] ; void solve () { int ans = MAXN ;#include <cstdio> #include <vector> #include <cstring> #include <algorithm> using namespace std ; typedef long long LL ; #define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i ) #define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i ) #define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i ) #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 2005 ; struct Node { char s[MAXN] ; char operator [] ( const int index ) const { return s[index] ; } char& operator [] ( const int index ) { return s[index] ; } } ; Node a[10] , ans ; int n ; void solve () { clr ( a , 0 ) ; scanf ( "%s" , a[0].s ) ; rep ( i , 1 , 10 ) rep ( j , 0 , n ) a[i][j] = ( a[i - 1][j] - '0' + 1 ) % 10 + '0' ; ans = a[0] ; rep ( i , 0 , 10 ) { rep ( j , 0 , n ) { if ( strcmp ( a[i].s + j , ans.s ) < 0 ) { rep ( k , 0 , n ) ans[k] = a[i][j + k] ; } a[i][n + j] = a[i][j] ; } } printf ( "%s\n" , ans.s ) ; } int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; } For ( i , 1 , n ) scanf ( "%d" , &a[i] ) ; For ( i , 2 , n - 1 ) { int tmp = 0 ; For ( j , 1 , i - 2 ) tmp = max ( tmp , a[j + 1] - a[j] ) ; rep ( j , i + 1 , n ) tmp = max ( tmp , a[j + 1] - a[j] ) ; tmp = max ( tmp , a[i + 1] - a[i - 1] ) ; ans = min ( tmp , ans ) ; } printf ( "%d\n" , ans ) ; } int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; }
496C. Removing Columns
贪心,不断减少判断的行,同时将矛盾的列删除。
#include <cstdio> #include <vector> #include <cstring> #include <algorithm> using namespace std ; typedef long long LL ; #define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i ) #define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i ) #define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i ) #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 105 ; struct Node { int x , y ; Node () {} Node ( int x , int y ) : x ( x ) , y ( y ) {} } ; Node t1[MAXN] ; Node t2[MAXN] ; int cnt ; char a[MAXN][MAXN] ; int n , m ; void solve () { Node *x = t1 , *y = t2 ; int ans = 0 ; cnt = n - 1 ; rep ( i , 0 , n - 1 ) x[i] = Node ( i , i + 1 ) ; rep ( i , 0 , n ) scanf ( "%s" , a[i] ) ; rep ( i , 0 , m ) { int flag = 0 ; int top = 0 ; rep ( j , 0 , cnt ) { if ( a[x[j].x][i] > a[x[j].y][i] ) { flag = 1 ; break ; } else if ( a[x[j].x][i] == a[x[j].y][i] ) { y[top ++] = x[j] ; } } if ( flag ) ++ ans ; else { swap ( x , y ) ; cnt = top ; } } printf ( "%d\n" , ans ) ; } int main () { while ( ~scanf ( "%d%d" , &n , &m ) ) solve () ; return 0 ; }
496D. Tennis Game
枚举T,然后每次走让一个人恰好赢的步数,由于我保存的是a[i] = x,即第i个位置编号为1的赢了第x小局,对编号2同理。然后每次就二分走一局需要的步数。。。最后将保存的答案按题意排序输出就好。
事实上,可以不需要二分的,只要保存a[x] = i,即编号为1的赢了第x小局时在位置i,同时预处理出每个1往回走遇到的第一个2的位置,对编号2同理。然后每次只要走t步就好了,不需要二分了。。。。
剩下的就是一些分类讨论模拟了,不细说了。
#include <cstdio> #include <vector> #include <cstring> #include <algorithm> using namespace std ; typedef long long LL ; #define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i ) #define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i ) #define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i ) #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 100005 ; struct Node { int s , t ; Node () {} Node ( int s , int t ) : s ( s ) , t ( t ) {} bool operator < ( const Node& a ) const { if ( s != a.s ) return s < a.s ; return t < a.t ; } } ; Node ans[MAXN] ; int top ; int fac[MAXN] , cnt ; int a[MAXN] ; int x[MAXN] , y[MAXN] ; int n ; int search ( int x , int a[] , int l = 1 , int r = n ) { while ( l < r ) { int m = ( l + r ) >> 1 ; if ( a[m] >= x ) r = m ; else l = m + 1 ; } return l ; } void solve () { int sum1 = 0 ; int sum2 = 0 ; top = 0 ; clr ( x , 0 ) ; clr ( y , 0 ) ; For ( i , 1 , n ) { scanf ( "%d" , &a[i] ) ; if ( a[i] == 1 ) sum1 ++ , x[i] = 1 ; else sum2 ++ , y[i] = 1 ; } For ( i , 1 , n ) x[i] += x[i - 1] , y[i] += y[i - 1] ; For ( o , 1 , n ) { int t = o ; int win1 = 0 , win2 = 0 ; int tmp1 = 0 , tmp2 = 0 ; while ( 1 ) { int X = search ( x[tmp1] + t , x ) ; int Y = search ( y[tmp2] + t , y ) ; //if ( t == 2 ) printf ( "%d %d\n" , X , Y ) ; if ( x[X] != x[tmp1] + t && y[Y] != y[tmp2] + t ) break ; if ( x[X] == x[tmp1] + t && y[Y] != y[tmp2] + t ) { ++ win1 ; tmp1 = tmp2 = X ; } else if ( x[X] != x[tmp1] + t && y[Y] == y[tmp2] + t ) { ++ win2 ; tmp1 = tmp2 = Y ; } else { if ( X < Y ) { ++ win1 ; tmp1 = tmp2 = X ; } else { ++ win2 ; tmp1 = tmp2 = Y ; } } } //if ( t == 2 ) printf ( "2333 %d %d\n" , win1 , win2 ) ; if ( win1 > win2 && search ( x[tmp1] , x ) == n ) { ans[top ++] = Node ( win1 , t ) ; } else if ( win1 < win2 && search ( y[tmp2] , y ) == n ) { ans[top ++] = Node ( win2 , t ) ; } } sort ( ans , ans + top ) ; printf ( "%d\n" , top ) ; rep ( i , 0 , top ) printf ( "%d %d\n" , ans[i].s , ans[i].t ) ; } int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; }
496E. Distributing Parts
这题呢,首先我们将两种区间都记录下来,按照左端点从大到小排个序,然后我们对于一个节目,将所有左端点大于等于这个节目左端点的人的右端点以及信息作为关键字插入到set,然后我们在set里面查找右端点小于等于节目右端点的最大的一个人,这个人标记为参加这个节目。每次我们都这么操作,只要最后看一下是否还有人没插入set或者set内还有元素,那么就无解,否则输出解。
这样的贪心为什么可以呢?因为假如我们每次按照上述方法选择,那么下一个节目区间的左端点一定小于等于这个节目的左端点,如果下一个节目的右端点大于等于这个节目的右端点,那么显然这样的分配是没问题的,如果下一个节目的右端点是小于这个节目的右端点的,那么我们便把下一个节目无法覆盖的位置覆盖了,保证没有漏掉,如果我们此时不是选择右端点小于等于节目右端点的最大的一个人,那么当下一个节目的右端点小于这一个节目的右端点时,便可能少覆盖了一个人,从而导致无解。大概就是这样=。=
#include <set> #include <cstdio> #include <cstring> #include <algorithm> using namespace std ; typedef long long LL ; #define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i ) #define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i ) #define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i ) #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 100005 ; const int INF = 0x3f3f3f3f ; struct Node { int x , y , k , idx ; bool operator < ( const Node& a ) const { return x > a.x ; } } ; struct Point { int x , idx ; Point () {} Point ( int x , int idx ) : x ( x ) , idx ( idx ) {} bool operator < ( const Point& a ) const { if ( x != a.x ) return x > a.x ; return idx < a.idx ; } } ; Node a[MAXN] , b[MAXN] ; set < Point > s ; set < Point > :: iterator it ; Point x ; int ans[MAXN] ; int n , m ; void solve () { s.clear () ; rep ( i , 0 , n ) { scanf ( "%d%d" , &a[i].x , &a[i].y ) ; a[i].idx = i + 1 ; } scanf ( "%d" , &m ) ; rep ( i , 0 , m ) { scanf ( "%d%d%d" , &b[i].x , &b[i].y , &b[i].k ) ; b[i].idx = i + 1 ; } sort ( a , a + n ) ; sort ( b , b + m ) ; int j = 0 ; rep ( i , 0 , m ) { int k = b[i].k ; while ( j < n && a[j].x >= b[i].x ) { s.insert ( Point ( a[j].y , a[j].idx ) ) ; ++ j ; } while ( k && !s.empty () ) { it = s.lower_bound ( Point ( b[i].y , 0 ) ) ; if ( it == s.end () ) break ; x = *it ; //printf ( "%d %d\n" , x.idx , b[i].idx ) ; ans[x.idx] = b[i].idx ; s.erase ( x ) ; -- k ; } } if ( j < n || !s.empty () ) { printf ( "NO\n" ) ; return ; } printf ( "YES\n" ) ; For ( i , 1 , n ) printf ( "%d%c" , ans[i] , i < n ? ' ' : '\n' ) ; } int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; }
相关文章推荐
- codeforces 789 div2 题解(AB水题,C dp,D图论)
- 【codeforces】Codeforces Round #311 (Div. 2)only 【题解】
- 【CodeForces】CodeForces Round #464 (Div. 2) 题解
- 【CodeForces】CodeForces Round #465 (Div. 2) 题解
- 【CodeForces】CodeForces Round #460 (Div. 2) 题解
- Codeforces Round #403 div2 (CodeForces - 782) 题解
- codeforces div1 D题解
- 【CodeForces】CodeForces Round #466 (Div. 2) 题解
- 【CodeForces】CodeForces Round #467 (Div. 1 + Div. 2) 题解
- 【codeforces】Codeforces Round #310 (Div. 1)【题解】
- codeforces 187 (div2)题解
- 【CodeForces】CodeForces Round #462 (Div. 1 + Div. 2) 题解
- 【codeforces】Codeforces Round #277 (Div. 2) 题解
- 【CodeForces】CodeForces Round #463 (Div. 1 + Div. 2) 题解
- Codeforces Round #404 div2 (CodeForces - 785ABCD) 题解
- 【codeforces】Codeforces Round #284 (Div. 1) 【题解】
- Codeforces 658A B C || VK Cup 2016 - Round 1 (Div. 2 Edition) A B C题解
- codeforces192 div2
- Codeforces 237 div2 B. Marathon(关于精度损失的教训)
- [CodeForces]Round #Pi (Div. 2) Aug/05/2015