【HDU】2014上海全国邀请赛——题目重现(感谢上海大学提供题目) 题解

来源:互联网 发布:淘宝仓库宝贝多久删除 编辑:程序博客网 时间:2024/06/10 04:20

写在最前:感谢bin神~


A:【HDU】5090Game with Pearls

将所有的数扔到优先队列中,每次取出最小的+k,如果正好等于cur,cur++,如果+k>cur说明无解,否则+k以后扔进优先队列中继续,因为数很小所以随便搞就好了。

#include <map>#include <string>#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;#pragma comment(linker, "/STACK:16777216")#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )#define clr( a , x ) memset ( a , x , sizeof a )#define ls ( o << 1 )#define rs ( o << 1 | 1 )#define lson ls , l , m#define rson rs , m + 1 , r#define root 1 , 1 , cnt#define mid ( ( l + r ) >> 1 )const int MAXN = 105 ;const int MAXH = 1000005 ;struct queue {int heap[MAXH] ;int point ;void clear () {point = 1 ;}int empty () {return point == 1 ;}void maintain ( int o ) {int p = o , l = o << 1 , r = o << 1 | 1 ;while ( o > 1 && heap[o] < heap[o >> 1] ) {swap ( heap[o] , heap[o >> 1] ) ;o >>= 1 ;}o = p ;while ( 1 ) {if ( l < point && heap[l] < heap[p] ) p = l ;if ( r < point && heap[r] < heap[p] ) p = r ;if ( p == o ) break ;swap ( heap[o] , heap[p] ) ;o = p , l = o << 1 , r = o << 1 | 1 ;}}void push ( int d ) {heap[point] = d ;maintain ( point ++ ) ;}void pop () {heap[1] = heap[-- point] ;maintain ( 1 ) ;}int top () {return heap[1] ;}} ;queue q ;int a[MAXN] ;int n , k ;void solve () {int cur = 1 ;q.clear () ;scanf ( "%d%d" , &n , &k ) ;For ( i , 1 , n ) {scanf ( "%d" , &a[i] ) ;q.push ( a[i] ) ;}while ( cur <= n ) {int u = q.top () ;q.pop () ;if ( u > cur ) {printf ( "Tom\n" ) ;return ;} else if ( u == cur ) {++ cur ;continue ;} else q.push ( u + k ) ;}printf ( "Jerry\n" ) ;}int main () {int T ;scanf ( "%d" , &T ) ;while ( T -- ) solve () ;return 0 ;}

B:【HDU】5091Beam Cannon

以每个点(x,y)作为宽w,高h的矩形的左下角,则答案即矩阵重叠次数最多的地方。我们可以这样:将每个矩阵拆成两条线段(x,x+w,y,1),(x,x+w,y+h,-1)(左端点,右端点,线段的高度,1表示进,-1表示出)。然后将线段按高度排序,高度相同的进的在前。然后题目就变成每遇到一条线段就区间加减,同时维护区间最大值。答案就是每条线段操作完后整个区间的最大值。线段树下标需要通过离散化宽度得到。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;#pragma comment(linker, "/STACK:16777216")#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )#define clr( a , x ) memset ( a , x , sizeof a )#define ls ( o << 1 )#define rs ( o << 1 | 1 )#define lson ls , l , m#define rson rs , m + 1 , r#define root 1 , 1 , cnt#define mid ( ( l + r ) >> 1 )const int MAXN = 20005 ;struct Seg {int l , r , h , f ;Seg () {}Seg ( int l , int r , int h , int f ) : l ( l ) , r ( r ) , h ( h ) , f ( f ) {}bool operator < ( const Seg& a ) const {if ( h != a.h ) return h < a.h ;return f > a.f ;}} ;Seg L[MAXN << 1] ;int maxv[MAXN << 3] ;int addv[MAXN << 3] ;int a[MAXN] , cnt ;int n , w , h ;int unique ( int n ) {sort ( a + 1 , a + n + 1 ) ;int cnt = 1 ;For ( i , 2 , n ) if ( a[cnt] != a[i] ) a[++ cnt] = a[i] ;return cnt ;}int search ( int x , int l = 1 , int r = cnt ) {while ( l < r ) {int m = mid ;if ( a[m] >= x ) r = m ;else l = m + 1 ;}return l ;}void update ( int L , int R , int v , int o , int l , int r ) {if ( L <= l && r <= R ) {maxv[o] += v ;addv[o] += v ;return ;}if ( addv[o] ) {addv[ls] += addv[o] ;addv[rs] += addv[o] ;maxv[ls] += addv[o] ;maxv[rs] += addv[o] ;addv[o] = 0 ;}int m = mid ;if ( L <= m ) update ( L , R , v , lson ) ;if ( m <  R ) update ( L , R , v , rson ) ;maxv[o] = max ( maxv[ls] , maxv[rs] ) ;}void solve () {int x , y , m ;m = cnt = 0 ;clr ( maxv , 0 ) ;clr ( addv , 0 ) ;scanf ( "%d%d" , &w , &h ) ;For ( i , 1 , n ) {scanf ( "%d%d" , &x , &y ) ;a[++ cnt] = x ;a[++ cnt] = x + w ;L[++ m] = Seg ( x , x + w , y , 1 ) ;L[++ m] = Seg ( x , x + w , y + h , -1 ) ;}int ans = 0 ;cnt = unique ( cnt ) ;sort ( L + 1 , L + m + 1 ) ;For ( i , 1 , m ) {int l = search ( L[i].l ) ;int r = search ( L[i].r ) ;update ( l , r , L[i].f , root ) ;ans = max ( ans , maxv[1] ) ;}printf ( "%d\n" , ans ) ;}int main () {while ( ~scanf ( "%d" , &n ) && ( n >= 0 ) ) solve () ;return 0 ;}

C:【HDU】5092Battle ships

题意感觉不好理解。。本意就是数塔,对于点(i,j),只能到达(i+1,j-1),(i+1,j),(i+1,j+1)。然后求从第1层到第n层的和最小的路径(起点为第1层任意一个,终点为第n层任意一个),最后要求输出符合条件的路径尽量靠近右边的,那么我们递归输出,能往右走就往右走就好了。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;#pragma comment(linker, "/STACK:16777216")#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )#define clr( a , x ) memset ( a , x , sizeof a )#define ls ( o << 1 )#define rs ( o << 1 | 1 )#define lson ls , l , m#define rson rs , m + 1 , r#define root 1 , 1 , cnt#define mid ( ( l + r ) >> 1 )const int MAXN = 105 ;const int INF = 0x3f3f3f3f ;int dp[MAXN][MAXN] ;int a[MAXN][MAXN] ;int n , m ;void print ( int x , int y ) {if ( x > 1 ) {if ( y < m && dp[x - 1][y + 1] + a[x][y] == dp[x][y] ) print ( x - 1 , y + 1 ) ;else if ( dp[x - 1][y] + a[x][y] == dp[x][y] ) print ( x - 1 , y ) ;else print ( x - 1 , y - 1 ) ;}printf ( "%d%c" , y , x == n ? '\n' : ' ' ) ;}void solve () {clr ( dp , INF ) ;scanf ( "%d%d" , &n , &m ) ;For ( i , 1 , n ) For ( j , 1 , m ) scanf ( "%d" , &a[i][j] ) ;clr ( dp[0] , 0 ) ;For ( i , 1 , n ) For ( j , 1 , m ) {if ( j > 1 ) dp[i][j] = min ( dp[i][j] , dp[i - 1][j - 1] ) ;dp[i][j] = min ( dp[i][j] , dp[i - 1][j] ) ;if ( j < m ) dp[i][j] = min ( dp[i][j] , dp[i - 1][j + 1] ) ;dp[i][j] += a[i][j] ;}int minv = INF , pos ;For ( i , 1 , m ) if ( dp[n][i] <= minv ) {minv = dp[n][i] ;pos = i ;}print ( n , pos ) ;}int main () {int T , cas = 0 ;scanf ( "%d" , &T ) ;while ( T -- ) {printf ( "Case %d\n" , ++ cas ) ;solve () ;}return 0 ;}

D:【HDU】5093Battle ships

二分图行列匹配= 、=。。行列重编号然后建边就好了,一行中每遇到一次障碍物就拆行,列同理。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;#pragma comment(linker, "/STACK:16777216")#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )#define clr( a , x ) memset ( a , x , sizeof a )#define ls ( o << 1 )#define rs ( o << 1 | 1 )#define lson ls , l , m#define rson rs , m + 1 , r#define root 1 , 1 , cnt#define mid ( ( l + r ) >> 1 )const int MAXN = 2505 ;const int MAXE = 2000000 ;struct Edge {int v , n ;Edge () {}Edge ( int v , int n ) : v ( v ) , n ( n ) {}} ;Edge E[MAXE] ;int H[MAXN] , cntE ;int vis[MAXN] , Time ;int R[55][55] , C[55][55] ;int row , col ;char G[55][55] ;int Lx[MAXN] , Ly[MAXN] ;int n , m ;void clear () {cntE = 0 ;clr ( H , -1 ) ;}void addedge ( int u , int v ) {E[cntE] = Edge ( v , H[u] ) ;H[u] = cntE ++ ;}int dfs ( int u ) {for ( int i = H[u] ; ~i ; i = E[i].n ) {int v = E[i].v ;if ( vis[v] == Time ) continue ;vis[v] = Time ;if ( Ly[v] == -1 || dfs ( Ly[v] ) ) {Ly[v] = u ;Lx[u] = v ;return 1 ;}}return 0 ;}int match () {int ans = 0 ;clr ( Lx , -1 ) ;clr ( Ly , -1 ) ;for ( int i = 1 ; i <= row ; ++ i ) {++ Time ;ans += dfs ( i ) ;}return ans ;}void solve () {row = col = 0 ;clear () ;clr ( R , 0 ) ;clr ( C , 0 ) ;scanf ( "%d%d" , &n , &m ) ;For ( i , 1 , n ) scanf ( "%s" , G[i] + 1 ) ;For ( i , 1 , n ) {++ row ;For ( j , 1 , m ) {if ( G[i][j] == '#' ) ++ row ;if ( G[i][j] == '*' ) R[i][j] = row ;}}For ( j , 1 , m ) {++ col ;For ( i , 1 , n ) {if ( G[i][j] == '#' ) ++ col ;if ( G[i][j] == '*' ) C[i][j] = col ;}}//For ( i , 1 , n ) For ( j , 1 , m ) printf ( "%d%c" , C[i][j] , j < m ? ' ' : '\n' ) ;For ( i , 1 , n ) For ( j , 1 , m ) if ( G[i][j] == '*' ) addedge ( R[i][j] , C[i][j] ) ;printf ( "%d\n" , match () ) ;}int main () {int T ;scanf ( "%d" , &T ) ;while ( T -- ) solve () ;return 0 ;}


E:【HDU】5094 Maze

状态压缩广搜,vis[x][y][S],(x,y)为坐标,S为当前拿到的钥匙的状态。注意一个位置可能有多把钥匙。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;#pragma comment(linker, "/STACK:16777216")#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )#define clr( a , x ) memset ( a , x , sizeof a )#define ls ( o << 1 )#define rs ( o << 1 | 1 )#define lson ls , l , m#define rson rs , m + 1 , r#define root 1 , 1 , cnt#define mid ( ( l + r ) >> 1 )const int MAXN = 55 ;const int MAXQ = 3000000 ;struct Node {int d , x , y , s ;Node () {}Node ( int d , int x , int y , int s ) : d ( d ) , x ( x ) , y ( y ) , s ( s ) {}} ;Node Q[MAXQ] ;int head , tail ;int map[MAXN * MAXN][4] ;bool vis[MAXN][MAXN][1024] ;int G[MAXN][MAXN] ;int path[4][2] = { { 1 , 0 } , { -1 , 0 } , { 0 , 1 } , { 0 , -1 } } ;//dulrint n , m , p ;int bfs () {head = tail = 0 ;clr ( vis , 0 ) ;Q[tail ++] = Node ( 0 , 0 , 0 , 0 ) ;vis[0][0][0] = 1 ;while ( head != tail ) {Node now = Q[head ++] ;if ( now.x == n - 1 && now.y == m - 1 ) return now.d ;rep ( i , 0 , 4 ) {int nx = now.x + path[i][0] ;int ny = now.y + path[i][1] ;if ( nx < 0 || nx >= n || ny < 0 || ny >= m ) continue ;int tmp = map[now.x * m + now.y][i] ;if ( tmp == -2 ) continue ;if ( tmp >= 0 && !( tmp & now.s ) ) continue ;int ns = now.s | G[nx][ny] ;if ( vis[nx][ny][ns] ) continue ;vis[nx][ny][ns] = 1 ;Q[tail ++] = Node ( now.d + 1 , nx , ny , ns ) ;}}return -1 ;}void solve () {int k , x1 , x2 , y1 , y2 , g , f ;int tot = n * m ;clr ( map , -1 ) ;clr ( G , 0 ) ;scanf ( "%d" , &k ) ;rep ( i , 0 , k ) {scanf ( "%d%d%d%d%d" , &x1 , &y1 , &x2 , &y2 , &g ) ;-- x1 ;-- x2 ;-- y1 ;-- y2 ;if ( x1 < x2 ) f = 0 ;else if ( x1 > x2 ) f = 1 ;else if ( y1 < y2 ) f = 2 ;else f = 3 ;map[x2 * m + y2][f ^ 1] = map[x1 * m + y1][f] = ( g ? ( 1 << ( g - 1 ) ) : -2 ) ;}scanf ( "%d" , &k ) ;rep ( i , 0 , k ) {scanf ( "%d%d%d" , &x1 , &y1 , &g ) ;-- x1 ;-- y1 ;-- g ;G[x1][y1] |= ( 1 << g ) ;}printf ( "%d\n" , bfs () ) ;}int main () {while ( ~scanf ( "%d%d%d" , &n , &m , &p ) ) solve () ;return 0 ;}

F:【HDU】5095Linearization of the kernel functions in SVM

照着题意做就好。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;#pragma comment(linker, "/STACK:16777216")#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )#define clr( a , x ) memset ( a , x , sizeof a )int a[10] ;char s[11] = "pqruvwxyz" ;void solve () {int x , flag = 0 ;rep ( i , 0 , 10 ) {scanf ( "%d" , &x ) ;if ( x == 0 ) continue ;if ( x > 0 && flag ) printf ( "+" ) ;if ( !flag ) flag = 1 ;if ( x < 0 ) printf ( "-" ) ;if ( 1 != abs ( x ) ) printf ( "%d" , abs ( x ) ) ;if ( i == 9 && 1 == abs ( x ) ) printf ( "%d" , abs ( x ) ) ;if ( i < 9 ) printf ( "%c" , s[i] ) ;}if ( !flag ) printf ( "0" ) ;printf ( "\n" ) ;}int main () {int T ;scanf ( "%d" , &T ) ;while ( T -- ) solve () ;return 0 ;}


H:【HDU】5097Page Rank

对着方法构造出G矩阵,然后p向量初始值设为1,然后就用pnext = G*pcur不断迭代,直到pnext-pcur<1e-10为止,然后输出此时的pcur或pnext都可以。(因为答案只要求保留两位小数,那么我们不必按照题目说的求那么精确,1e-5就可以了,再大我的算法就WA了。。)

因为这个计算是一定收敛(也就是一定有解),且收敛速度飞快=、=所以这样暴力搞一点问题都没有。。。具体什么的还是自己查找一下吧,网上还是有关于这个的很多信息的。

(这题p向量初始值必须全1。。。题目有说明吗???)

#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;#pragma comment(linker, "/STACK:16777216")#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )#define clr( a , x ) memset ( a , x , sizeof a )#define cpy( a , x ) memcpy ( a , x , sizeof a )const int MAXN = 3005 ;const double eps = 1e-5 ;double G[MAXN][MAXN] ;double cur[MAXN] , next[MAXN] ;char buf[MAXN] ;int n ;inline int dcmp ( double x ) {return ( x > eps ) - ( x < -eps ) ;}bool check () {rep ( i , 0 , n ) if ( dcmp ( cur[i] - next[i] ) ) return 0 ;return 1 ;}void solve () {clr ( G , 0 ) ;clr ( cur , 0 ) ;clr ( next , 0 ) ;rep ( i , 0 , n ) next[i] = 1 ;rep ( i , 0 , n ) {scanf ( "%s" , buf ) ;int cnt = 0 ;rep ( j , 0 , n ) if ( buf[j] - '0' ) ++ cnt ;if ( cnt ) rep ( j , 0 , n ) if ( buf[j] - '0' ) G[j][i] = 0.85 / cnt ;rep ( j , 0 , n ) G[j][i] += 0.15 / n ;}while ( !check () ) {cpy ( cur , next ) ;rep ( i , 0 , n ) {next[i] = 0 ;rep ( j , 0 , n ) next[i] += G[i][j] * cur[j] ;}}rep ( i , 0 , n ) printf ( "%.2f%c" , next[i] , i < n - 1 ? ' ' : '\n' ) ;}int main () {while ( ~scanf ( "%d" , &n ) ) solve () ;return 0 ;}


I:【HDU】5098Smart Software Installer

如果我们给有从属关系的两个设备建边(u,v)表示安装v前需先安装完成u。因为带*的重启后才安装完成,所以在一条有向路径上的所有带*设备要分别重启。于是我们给每个点一个点权,0表示这个点不需要重启,1表示这个点需要重启,于是我们建完图跑一遍DAG最长路就好了。题目已经说明此图是无环的了。

可能本题的难点不在发现这个题怎么写。。而在处理字符串上。。。。

#include <map>#include <string>#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;#pragma comment(linker, "/STACK:16777216")#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )#define clr( a , x ) memset ( a , x , sizeof a )#define ls ( o << 1 )#define rs ( o << 1 | 1 )#define lson ls , l , m#define rson rs , m + 1 , r#define root 1 , 1 , cnt#define mid ( ( l + r ) >> 1 )const int MAXN = 1005 ;const int MAXE = 1000005 ;struct Edge {int v , n ;Edge () {}Edge ( int v , int n ) : v ( v ) , n ( n ) {}} ;Edge E[MAXE] ;int H[MAXN] , cntE ;int d[MAXN] , num[MAXN] ;int point ;char buf[10000] , s[10000] ;int in[MAXN] ;int Q[MAXN] , head , tail ;map < string , int > mp ;void clear () {cntE = 0 ;point = 0 ;mp.clear () ;clr ( in , 0 ) ;clr ( H , -1 ) ;clr ( num , 0 ) ;}void addedge ( int u , int v ) {E[cntE] = Edge ( v , H[u] ) ;H[u] = cntE ++ ;}void topo () {clr ( d , 0 ) ;head = tail = 0 ;for ( int i = 1 ; i <= point ; ++ i ) if ( !in[i] ) {Q[tail ++] = i ;d[i] = num[i] ;}while ( head != tail ) {int u = Q[head ++] ;for ( int i = H[u] ; ~i ; i = E[i].n ) {int v = E[i].v ;if ( d[v] < d[u] + num[v] ) d[v] = d[u] + num[v] ;if ( 0 == -- in[v] ) Q[tail ++] = v ;}}int ans = 0 ;for ( int i = 1 ; i <= point ; ++ i ) ans = max ( ans , d[i] ) ;printf ( "%d\n" , ans ) ;}void solve () {int u , v ;clear () ;while ( 1 ) {if ( !gets ( buf ) ) break ;if ( !buf[0] ) break ;int cnt = 0 , i ;for ( i = 0 ; buf[i] != ':' ; ++ i ) if ( buf[i] != '*' ) s[cnt ++] = buf[i] ;s[cnt] = 0 ;if ( !mp.count ( s ) ) u = mp[s] = ++ point ;else u = mp[s] ;if ( buf[i - 1] == '*' ) num[u] = 1 ;cnt = 0 ;if ( buf[i + 1] == 0 ) continue ;for ( i += 2 ; buf[i] ; ++ i ) {if ( buf[i] == ' ' || !buf[i + 1] ) {if ( buf[i + 1] == 0 ) s[cnt ++] = buf[i] ;s[cnt] = 0 ;if ( !mp.count ( s ) ) v = mp[s] = ++ point ;else v = mp[s] ;addedge ( v , u ) ;++ in[u] ;cnt = 0 ;} else s[cnt ++] = buf[i] ;}}topo () ;}int main () {int T , cas = 0 ;scanf ( "%d" , &T ) ;getchar () ;getchar () ;while ( T -- ) {printf ( "Case %d: " , ++ cas ) ;solve () ;}return 0 ;}

J:【HDU】5099Comparison of Android versions

第一个字符是版本号,第二个字符是这个版本的分支,接下来三个字符是时间,最后一个字符我也不知道是什么。

第一个输出为两个字符串的版本号的比较。

第二个输出为时间的比较,如果他们的分支相同时要带上最后一个字符一起比较,否则不带。比较的大小就是字符串大小的比较。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;char s1[7] , s2[7] ;void solve () {scanf ( "%s%s" , s1 , s2 ) ;if ( s1[0] > s2[0] ) printf ( ">" ) ;else if ( s1[0] == s2[0] ) printf ( "=" ) ;else printf ( "<" ) ;printf ( " " ) ;if ( s1[0] != s2[0] || s1[1] != s2[1] ) s1[5] = s2[5] = 0 ;int cmp = strcmp ( s1 + 2 , s2 + 2 ) ;if ( cmp < 0 ) printf ( "<" ) ;else if ( cmp == 0 ) printf ( "=" ) ;else printf ( ">" ) ;printf ( "\n" ) ;}int main () {int T , cas = 0 ;scanf ( "%d" , &T ) ;while ( T -- ) {printf ( "Case %d: " , ++ cas ) ;solve () ;}return 0 ;}

0 0
原创粉丝点击