给一个全为正整数的N*N矩阵,要从左上角走到右下角,每次只能向右或向下,问路径上所有数字乘积末尾的零最少有多少个.
我一度以为这道题不具有最优子结构性质啊喂,还有后效性啊喂
思考了一个小时然后看了syl题解啊喂
一会建立一个题集合,就叫莫名其妙的卡想法.
首先,如果这道题是dp的话,显然是一个二维的位置dp,只要求i,j到n,n的信息即可.
显然末尾0的个数是由2因子和5因子的个数决定的,为min(n2,n5)
我卡的地方,也就是思维的关键难点在于:一个节点到底该保存什么信息?(状态表示)
保存末尾0最小值的话,随意构造一组数据就能卡掉.
因为前方的数据是未知的,换句话说,保存最小值是有后效性的.
如果对于每个n2的值,都保存一个最小的n5的值,是可以走通的,但是复杂度会超(n2最高100000,一共相当于n^3还多)
但是又不能轻易判定两个n2,n5数对的大小关系来决定存哪个,比如(1,7)和(2,6),需要哪个作为当前节点的信息完全取决于之前的节点,同样有后效性,不能覆盖.
以上的思考过程中我忽略了一个性质:如果获得了某个节点的最小n2和最小n5值(记为m2和m5),注意不用在同一路径上
那么最小末尾0的个数就是min(m2,m5).
因为走m2的路径,n5一定大于m5.同理走m5的路径,n2一定大于m2.
所以状态信息的表示分成了dp2和dp5,即一个节点的m2和m5.求解答案时,取min即可.
先写代码,再总结.
状态表示:dp2[i][j],dp5[i][j]分别表示点i,j到点n,n的最少2因子个数和最少5因子个数.
边界条件:dp[n][n]=save[n][n]
状态转移:dp[i][j]=min(dp[i+1][j],dp[i][j+1])+save[i][j] 注意边界的情况.
if(j==n) dp[i][j]=dp[i+1][j]+save[i][j]
if(i==n) dp[i][j]=dp[i][j+1]+save[i][j]
/* LittleFall : Hello! */
#include
using namespace std;
inline int read();
inline void write(int x);
const int M = 1024;
int save[M][M][2],dp[M][M][2]; //0为n2,1为n5
int main(void)
{
#ifdef _LITTLEFALL_
freopen("in.txt","r",stdin);
#endif
//std::cin.sync_with_stdio(false);
int n;
while(scanf("%d",&n)!=EOF)
{
memset(save,0,sizeof(save));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
long long tmp;
scanf("%lld",&tmp);
while(!(tmp&1))
{
save[i][j][0]++;
tmp>>=1;
}
while(tmp%5==0)
{
save[i][j][1]++;
tmp/=5;
}
}
memset(dp,1,sizeof(dp));
dp[n][n][0]=dp[n][n][1]=0;
for(int i=n;i;i--)
for(int j=n;j;j--)
{
if(i0]=min(dp[i][j][0],dp[i+1][j][0]);
dp[i][j][1]=min(dp[i][j][1],dp[i+1][j][1]);
}
if(j0]=min(dp[i][j][0],dp[i][j+1][0]);
dp[i][j][1]=min(dp[i][j][1],dp[i][j+1][1]);
}
dp[i][j][0]+=save[i][j][0];
dp[i][j][1]+=save[i][j][1];
}
printf("%d\n",min(dp[1][1][0],dp[1][1][1]) );
}
return 0;
}
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
先回去,要锁门了.
总结:节点的状态表示不一定要是结果.甚至可以同时进行多个dp,最后合并成结果.