G.小红的数轴移动(二)

小红的数轴移动(二)

https://ac.nowcoder.com/acm/contest/91177/G

alt

Solution

首先看到这个题,大家的第一印象是如何克服第二次操作朝向原点方向移动距离这个操作。

让我们来思考一个问题,如果我们只考虑只执行第一次操作,我们可以把这个问题变化为背包问题。用背包问题找到总距离的最小值,并且用last[i][j]保存上一次的操作来得出操作的方案。(背包问题的经典操作)

现在我们有了操作的方案,我们怎么去考虑第二个问题?

我们可以采取构造的方式,我们的操作有两种,一个是加上一个数,一个是减去一个数。将操作分为两个集合。

如果当前在正半轴,我们就用减去一个数的集合里挑选一个操作并且减去这个数,如果在正半轴,同理。最后一定能够回到原点。

剩下的操作都是不操作的,那我们直接放到末尾即可。

在赛时,这个题貌似数据出锅了,出现了无解的情况23333。可能这才是通过率低的缘故吧。

代码实现:

const int N = 4050 ;
 
// const int N = 1e6 + 10 ;
typedef pair<int , int> pii ;
typedef pair<double , double> pdd ;
const int inf = 1e9 + 10 ;
const int M = 2 * N ; 
const int mod = 998244353 ;
const double pi = acos(-1) ; 
 
int delta = 2010 ;
int dp[N][N] ;
int last[N][N] ; 
int a[N] ;
 
void solve() {
    memset(dp , 0x3f , sizeof dp) ;
    int n = read() , x = read() ;
    dp[0][delta + x] = 0 ;
    for(int i = 1 ; i <= n ; i ++) a[i] = read() ;
    for(int i = 0 ; i < n ; i ++){
        for(int j = 0 ; j < N ; j ++){
            if(j + a[i + 1] < N){
                if(dp[i + 1][j + a[i + 1]] > dp[i][j] + a[i + 1]){
                    dp[i + 1][j + a[i + 1]] = dp[i][j] + a[i + 1] ;
                    last[i + 1][j + a[i + 1]] = 1 ;
                }
            }
            if(dp[i + 1][j] > dp[i][j]){
                dp[i + 1][j] = dp[i][j] ;
                last[i + 1][j] = 0 ;  
            }
            if(j - a[i + 1] >= 0){
                if(dp[i + 1][j - a[i + 1]] > dp[i][j] + a[i + 1]){
                    dp[i + 1][j - a[i + 1]] = dp[i][j] + a[i + 1] ;
                    last[i + 1][j - a[i + 1]] = -1 ;
                }
            }
        }
    }
    if(dp[n][delta] > 1e7){
        int ans = 0 ;
        for(int i = 1 ; i <= n ; i ++) ans += a[i] ;
        write(ans , '\n') ;
        for(int i = 1 ; i <= n ; i ++) write(i , ' ') ;
         
        return ; 
    }
 
    cout << dp[n][delta] << endl ;
    vector<int> xx,yy,zz;
    int ax = n , ay = delta ;
    while(ax){
        if(last[ax][ay] == 0) xx.push_back(ax) ;
        else if(last[ax][ay] > 0) yy.push_back(ax) ;
        else zz.push_back(ax) ;
        ay -= last[ax][ay] * a[ax] ;
        ax -- ; 
    }   
    ay = delta + x ;
    while(ay != delta){
        if(ay < delta){
            ay += a[yy.back()] ;
            write(yy.back() , ' ') ;
            yy.pop_back() ; 
        }else{
            ay -= a[zz.back()] ;
            write(zz.back() , ' ') ;
            zz.pop_back() ; 
        }
    }
    while(xx.size()){
        write(xx.back() , ' ') ;
        xx.pop_back() ;
    }
}
 
全部评论

相关推荐

01-17 18:15
已编辑
门头沟学院 前端工程师
从上午约我面试然后他迟到,然后中午发消息打电话给我说重约面试时间,我就该意识到。【管理不规范,只是这家公司最小的问题】他妈一个不是技术的人来给我技术面。。。连vvue什么?连react是什么?连普通的HTTP请求是什么?这些东西都不懂的人来给我做技术面,我真的。。。。他妈浪费我40分钟。。一天面了三场,这家公司属实牛逼。不停的问我说上班下班时间谁来派任务公司在哪个区发展怎么样,公司的管理模式什么样,培养机制怎么样带教负责什么。如果出bug了谁来负责。我真的求你了别闹了。我答了15分钟,我已经很不想回答了。然后他就问了我一些很招笑的面试问题。问我前端框架架构设计怎么设计,Websocket可以实现SSE吗??最后还要我硬说,为什么我们公司没转正?为什么?为什么?我说我怎么知道。。这是领导决定,又不是我决定,他说让我分析一下。。。我真的草了,这个人是来搞我的吗?我最后问我说这个没有技术面,他说他就是技术面虽然我今天面的另外两家也很逆天。一个人不停的吹牛,自己100人的公司是全国前几,吹牛了一个小时。我中途几次想跑,真的是底下玩手机在听他那吹牛。。然后最后来了句说,我承诺的东西要实现哦,不然的话,公司会追责的,我我请问我承诺了什么?从头到尾也没有说让我承诺什么。而且我只是作为一个小小的前端卡拉咪,应届生。我要承担什么??好崩溃。。好崩溃的,一天面了三场。两家1000-9999的公司。面试官问的都很傻逼,甚至有些东西我问他估计都答不出来。。&nbsp;我这是在干嘛呀?浪费我一天的时间,我的奶奶。。我本来是抱着说我很菜,我要面试中发现自己的问题,现在来看他妈的这三场面试,面试本身就是问题。。
点赞 评论 收藏
分享
评论
2
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务