传送门:【HDU】4870 Rating
题目分析:虽然题目看起来是两个帐号紧密相联的,但是由于每次都是只选择rating低的去打,其实可以将这个过程看成:先将一个号打到19级,然后再将一个号打到20级。
这样我们就列一个状态转移方程:dp[ i ] = p * dp[i + 1] + ( 1 - p ) * dp[i - 2] + 1。
然后做两次高斯消元(一次19,一次20 )即可。注意细节问题。
代码如下:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define REV( i , n ) for ( int i = n - 1 ; i >= 0 ; -- i )
#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define FOV( i , a , b ) for ( int i = a ; i >= b ; -- i )
#define REPF( i , a , b ) for ( int i = a ; i < b ; ++ i )
#define REPV( i , a , b ) for ( int i = a - 1 ; i >= b ; -- i )
#define CLR( a , x ) memset ( a , x , sizeof a )
const int MAXN = 22 ;
const double eps = 1e-10 ;
double p ;
double a[MAXN][MAXN] ;
int sgn ( double x ) {
return ( x > eps ) - ( x < -eps ) ;
}
void guass ( int n , int m ) {
for ( int r = 0 , c = 0 ; r <= n , c <= m ; ++ r , ++ c ) {
int tmp = r ;
FOR ( i , r + 1 , n )
if ( sgn ( fabs ( a[i][c] ) - fabs ( a[tmp][c] ) ) > 0 )
tmp = i ;
if ( sgn ( a[tmp][c] ) == 0 ) {
--r ;
continue ;
}
if ( tmp != r )
FOR ( i , c , m )
swap ( a[r][i] , a[tmp][i] ) ;
FOV ( i , m , c )
a[r][i] /= a[r][c] ;
FOR ( i , 0 , n )
if ( sgn ( a[i][c] ) && i != r )
FOV ( j , m , c )
a[i][j] -= a[i][c] * a[r][j] ;
}
}
double solve ( int n ) {
CLR ( a , 0 ) ;
FOR ( i , 0 , n ) {
if ( i == 0 ) {
a[i][i] = p ;
a[i][i + 1] = -p ;
a[i][n + 1] = 1 ;
}
else if ( i == 1 ) {
a[i][i] = 1 ;
a[i][i - 1] = p - 1 ;
a[i][i + 1] = -p ;
a[i][n + 1] = 1 ;
}
else if ( i != n ) {
a[i][i] = 1 ;
a[i][i + 1] = -p ;
a[i][i - 2] = p - 1 ;
a[i][n + 1] = 1 ;
}
else {
a[i][i] = 1 ;
}
}
guass ( n , n + 1 ) ;
return a[0][n + 1] ;
}
int main () {
while ( ~scanf ( "%lf" , &p ) )
printf ( "%.6f\n" , solve ( 19 ) + solve ( 20 ) ) ;
return 0 ;
}