CF2B The least round way 题解

都是泪呀。。。↑

题目传送门

题意(直接复制了QWQ)

题目描述

给定由非负整数组成的\(n \times n\)的正方形矩阵,你需要寻找一条路径:
以左上角为起点,
每次只能向右或向下走,
以右下角为终点 并且,如果我们把沿路遇到的数进行相乘,积应当是最小“round”,换句话说,应当以最小数目的0的结尾.

输入格式

第一行包含一个整数 \((2 \leq n \leq 1000)\),\(n\)为矩阵的规模,接下来的\(n\)行包含矩阵的元素(不超过\(10^9\)的非负整数).

输出格式

第一行应包含最小尾0的个数,第二行打印出相应的路径(译注:D为下,R为右)

思路

楼下其实说得蛮清楚了,我主要就是说一下坑。。。
构成末尾是0的只能是\(2^a\)与\(5^b\)相乘,所得的0的个数为\(min(a,b)\),所以,只要2、5分别dp一遍,取一下上与左的最小值就好啦。。。最后求路径时递归求一遍就好啦。。。

TLE的小朋友们看这里啦。。。

TLE的小朋友们看这里啦。。。

TLE的小朋友们看这里啦。。。

(重要的事情说三遍)

此题特别会卡时。
比如说一开始预处理每个数是\(2^a\)与\(2^b\)时,需要将此数不间断地除下去,为什么呢?因为卡常数。。。也许时我RP的原因吧。。。卡了半天,终于卡过去了。。。
具体详见代码:

代码

(我知道你要看这个)

#include<bits/stdc++.h>
using namespace std;//奇丑无比的码风
int n,a[1010][1010],f[2][1010][1010],dp[2][1010][1010];
int ans,qx,qy;
bool ff;
inline int get2(register int x,register int y){
    if(a[x][y]==0){return 0;} //特判
    register int pt=0;
    while(a[x][y]%2==0) ++pt,a[x][y]/=2; //卡常数
    return pt;
}
inline int get5(register int x,register int y){
    if(a[x][y]==0){return 0;} //特判
    register int pt=0;
    while(a[x][y]%5==0) ++pt,a[x][y]/=5; //卡常数
    return pt;
}
inline void print(register int k,register int x,register int y,register int first){
    if(x==1&&y==1) ;
    else if(x==1) print(k,x,y-1,0);
    else if(y==1) print(k,x-1,y,1);
    else if(dp[k][x][y]==dp[k][x-1][y]+f[k][x][y]) print(k,x-1,y,1);
    else print(k,x,y-1,0);
    if(first==6666) return ;
    putchar(first==0?'R':'D'); //一开始在n,n点时不需要输出
    return ;
}
int main(){
    while(cin>>n){
        ff=0;qx=0;qy=0;
        for(register int i=1;i<=n;i++){
            for(register int j=1;j<=n;j++){
                cin>>a[i][j];
                if(a[i][j]==0){
                    qx=i;qy=j;
                    ff=1;
                }
            }
        }
        for(register int i=1;i<=n;i++){
            for(register int j=1;j<=n;j++){
                f[0][i][j]=get2(i,j);
                f[1][i][j]=get5(i,j);
            }
        }
        memset(dp,63,sizeof(dp));
        for(register int i=1;i<=n;i++)
            for(register int j=1;j<=n;j++){
                dp[0][i][j]=min(dp[0][i][j],dp[0][i-1][j]);
                dp[0][i][j]=min(dp[0][i][j],dp[0][i][j-1]);//从左格子与上格子中取最小值
                if(i==1&&j==1) dp[0][i][j]=0;
                dp[0][i][j]+=f[0][i][j];
            }
        for(register int i=1;i<=n;i++)
            for(register int j=1;j<=n;j++){
                dp[1][i][j]=min(dp[1][i][j],dp[1][i-1][j]);
                dp[1][i][j]=min(dp[1][i][j],dp[1][i][j-1]);//从左格子与上格子中取最小值
                if(i==1&&j==1) dp[1][i][j]=0;
                dp[1][i][j]+=f[1][i][j];
            }
        ans=min(dp[0][n][n],dp[1][n][n]);//初步ans
        if(ans>1&&ff==1){ //特判有0的情况,如果有0,那么答案只有0或1.
            putchar('1');
            putchar('\n');
            for(register int i=1;i<qx;i++) putchar('D');
            for(register int i=1;i<qy;i++) putchar('R');
            for(register int i=qx;i<n;i++) putchar('D');
            for(register int i=qy;i<n;i++) putchar('R');
            putchar('\n');
        }else{
            cout<<ans;
            putchar('\n');
            if(dp[0][n][n]<dp[1][n][n]) print(0,n,n,6666); //分2、5讨论
            else print(1,n,n,6666);
            putchar('\n');
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/yzx1798106406/p/10046601.html

时间: 2024-10-27 19:24:54

CF2B The least round way 题解的相关文章

Codeforces Round #541 题解

codeforces Round #541 C 题意 给你100个人,让你将它们围成一个圆,使得:"任意相邻的两人身高差的绝对值" 中的最大值 最小 题解 显然的构造方法:先排序,让所有人1 2 报数,报2的出列,排尾变排头接到报 1 的原队列后面 证明: 显然这样的构造方法保证身高差最大为 max{(a[i+2]-a[i]) }(i=1..n,环状,a[i]升序): 我们可以说明对于任意的i,身高差至少为(a[i+2]-a[i]), 如果我们将每个人看成一个点,相邻关系看成一条无向边

CFEducational Codeforces Round 66题解报告

CFEducational Codeforces Round 66题解报告 感觉丧失了唯一一次能在CF上超过wqy的机会QAQ A 不管 B 不能直接累计乘法打\(tag\),要直接跳 C 考虑二分第\(k\)小的值 那么问题就变成了 每一个数变成了\([x-mid,x+mid]\)的一段区间,如果有一个位置被覆盖了超过\(k\)次 那么\(mid\)一定合法 类似括号匹配 每次碰到左端点就贡献+1 右端点就统计答案然后-1 维护答案的同时顺便维护位置就好了 #include<cstdio>

CF2B The least round way

CF2B The least round way message1: 脚造的垃圾hack数据: 3 0 1 1 1 1 1 1 1 1 ans: 1 DDRR 数据2: 3 0 1 1 1 1 0 1 1 1 ans: 1 DDRR dp 0由2×5组成 预处理每个位置2因子.5因子个数 f[i][j][k]表示dp到(i,j),k因子至少有几个 输出路径只要倒着dfs一遍即可 代码: #include<bits/stdc++.h> using namespace std; int n; in

“玲珑杯”ACM比赛 Round #19题解&amp;源码【A,规律,B,二分,C,牛顿迭代法,D,平衡树,E,概率dp】

A -- simple math problem Time Limit:2s Memory Limit:128MByte Submissions:1599Solved:270 SAMPLE INPUT 5 20 1314 SAMPLE OUTPUT 5 21 1317 SOLUTION “玲珑杯”ACM比赛 Round #19 题目链接:http://www.ifrog.cc/acm/problem/1145 分析: 这个题解是官方写法,官方代码如下: 1 #include <iostream>

CF Round #631 题解

\(Codeforces\) \(Round\) \(631\) A.Dreamoon and Ranking Collection 题目大意: \(n\)轮比赛,每轮比赛排名已经给出,还可以进行额外的\(m\)场比赛 问:所有比赛进行完后,最多可以收集到从\(1\)开始的多少个连续名次 题解: 用一个数组统计一下排名的出现情况,然后扫一遍添加\(m\)个缺失名次即可 代码: #include<iostream> #include<cstdio> #include<cstdl

JSOI Round 2题解

强行一波题解骗一个访问量好了... http://blog.csdn.net/yanqval/article/details/51457302 http://absi2011.is-programmer.com/posts/200822.html http://absi2011.is-programmer.com/posts/200920.html orz js省队神犇↑ Day1 最佳团队(team) 给一个n+1个点的树,每个点有价值pi和费用si,求一个包含根的大小为m+1的联通块,使价值

codeforces Round#332Div2 题解

codeforces Round#332Div2 AB 签到题 比较激动,纷纷WA了一发. C 把数组h复制给a,然后对a数组排序. 对h和a数组,求前缀和,有多少个位置满足\(\sum a[i] = \sum h[i]\), 就最多能分成多少块. D 我们枚举更短的那条边,这样的边不会太多. 然后求,更长的那条边. E 符合xxx限定条件的图的计数问题.数据范围很状压. 我们用dp[mask][root]表示,集合mask里的点,以root为根,不违背限定条件的方案数. 接下来考虑dp[mas

Codeforces Educational Codeforces Round 54 题解

题目链接:https://codeforc.es/contest/1076 A. Minimizing the String 题意:给出一个字符串,最多删掉一个字母,输出操作后字典序最小的字符串. 题解:若存在一个位置 i 满足 a[i] > a[i+1],若不删除 a[i] 则后续操作不可能更优. 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define ull unsigned

Educational Codeforces Round 55 题解

题解 CF1082A [Vasya and Book] 史上最难A题,没有之一 从题意可以看出,翻到目标页只有三种办法 先从\(x\)到\(1\),再从\(1\)到\(y\) 先从\(x\)到\(n\),再从\(n\)到\(y\) 直接从\(x\)到\(y\) 三种的必要条件分别是 \((y-1)\mod d \equiv 0\) \((n-y)\mod d \equiv 0\) \(|x-y|\mod d \equiv 0\) 所以如果上面三种都不满足的话就输出\(-1\) 不然就取最小的输出