題目傳送門
題意:
n*n的矩陣,每個格子有一個非負整數。起點在左上角的格子,每次移動可以向下或向右。不能越界。終點是右下角的格子。
把路徑上的數乘起來,使乘積的後導0個數最少。0認爲有一個後導0。
數據範圍: , 。 是矩陣上的數。
題解:
從起點到終點路徑上的數的乘積因子中2的個數設爲x,5的個數設爲y。如果不考慮0,答案就是min(x,y)。
如果路徑上有0,那麼後導0個數爲1,需特判。
這道題的2因子和5因子是獨立的。意識到這點就完了。
假設x的最小值是minx,y的最小值是miny。
設從起點到終點路徑上2的因子數是minx時,5的因子數是y。那麼(minx,y)是有關的二元組。
設從起點到終點路徑上5的因子數是miny時,2的因子數是x。那麼(x,miny)是有關的二元組。
不妨設minx<miny,那麼這個時候minx < miny <= y。容易知道路徑上後導0個數是minx。
然後dp並記錄路徑就好了。
感受:
這道題真的把我educate了。
這道題一直WA在變量名寫重了。前面那麼多測例沒WA是因爲在第31個測例纔用到寫重的部分。
代碼:
#include<bits/stdc++.h>
using namespace std ;
const int maxn = 1005 ;
const int inf = 0x3f3f3f3f ;
int n ;
int num[maxn][maxn][2] ;
int dp[maxn][maxn][2] , p[maxn][maxn][2] ;
void change(int a , int b , int c , int d , int id , int f)
{
int x = dp[a][b][id] + num[c][d][id] ;
int y = dp[c][d][id] ;
if(x < y)
{
dp[c][d][id] = x ;
p[c][d][id] = f ;
}
}
void dfs(int x , int y , int id)
{
if(x == 1 && y == 1) return ;
if(p[x][y][id] == 0) dfs(x - 1 , y , id) ;
else dfs(x , y - 1 , id) ;
if(p[x][y][id] == 0) printf("D") ;
else printf("R") ;
}
void solve(bool flag , int x , int y)
{
int ans = inf ;
if(flag) ans = 1 ;
dp[1][1][0] = num[1][1][0] ;
dp[1][1][1] = num[1][1][1] ;
for(int i = 1 ; i <= n ; i ++)
for(int j = 1 ; j <= n ; j ++)
{
change(i , j , i + 1 , j , 0 , 0) ;
change(i , j , i + 1 , j , 1 , 0) ;
change(i , j , i , j + 1 , 0 , 1) ;
change(i , j , i , j + 1 , 1 , 1) ;
}
int z = min(dp[n][n][0] , dp[n][n][1]) ;
if(z >= ans)
{
printf("1\n") ;
for(int i = 1 ; i <= x - 1 ; i ++) printf("D") ;
for(int i = 1 ; i <= y - 1 ; i ++) printf("R") ;
for(int i = 1 ; i <= n - x ; i ++) printf("D") ;
for(int i = 1 ; i <= n - y ; i ++) printf("R") ;
printf("\n") ;
}
else
{
printf("%d\n" , z) ;
if(dp[n][n][0] < dp[n][n][1]) dfs(n , n , 0) ;
else dfs(n , n , 1) ;
printf("\n") ;
}
}
int main()
{
bool flag = 0 ;
int x = 0 , y = 0 ;
scanf("%d" , &n) ;
memset(num , 0 , sizeof(num)) ;
memset(dp , inf , sizeof(dp)) ;
for(int i = 1 ; i <= n ; i ++)
for(int j = 1 ; j <= n ; j ++)
{
int z ;
scanf("%d" , &z) ;
if(z == 0) flag = 1 , x = i , y = j ;
else
{
while(z % 2 == 0) z /= 2 , num[i][j][0] ++ ;
while(z % 5 == 0) z /= 5 , num[i][j][1] ++ ;
}
}
solve(flag , x , y) ;
return 0 ;
}