• [JOI2014] 小笼包


    题面 : https://www.ioi-jp.org/joi/2013/2014-yo/2014-yo-t6/2014-yo-t6.html

    题解

    dp + 康托展开

    一看这题不知道怎么处理

    只能枚举顺序来处理小笼包的价值

    然后又发现这个(d[])只有7

    所以可以状压他们的顺序

    现学的康托展开将前7个的顺序存储起来

    (f[i][S])表示到第i个小笼包,包括第i个小笼包的前7个的先后顺序是什么

    然后枚举第i+1个小笼包的顺序

    算下对前面的贡献和前面的对ta的贡献

    暴力dp即可

    时间复杂度(O(7!*n*7))

    可以通过此题

    代码

    
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int M = 105 ;
    const int N = 5050 ;
    using namespace std ;
    inline int read() {
        char c = getchar() ; int x = 0 , w = 1 ;
        while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
        while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
        return x*w ;
    }
    
    int n ;
    int v[M] , d[M] , Ans ;
    int fac[9] , f[M][N] ;
    int p[9] , w[9] ;
    bool vis[9] ;
    inline int Merge() {
        int Ans = 0 ;
        for(int i = 1 , ret ; i <= 7 ; i ++) {
            ret = 0 ;
            for(int j = i + 1 ; j <= 7 ; j ++)
                if(w[i] > w[j])
                    ++ ret ;
            Ans += ret * fac[7 - i] ;
        }
        return Ans + 1 ;
    }
    inline void Split(int x) {
        memset(vis , false , sizeof(vis)) ;
        x -= 1; 
        for(int i = 1 , ret , now ; i <= 7 ; i ++) {
            ret = x / fac[7 - i] ;
            for(now = 1 ; now <= n ; now ++)
                if(!vis[now]) {
                	if(!ret) break ;
                	ret -- ;
                }
            p[i] = now ;
            vis[now] = true ;
            x %= fac[7 - i] ;
        }
    }
    int main() {
        n = read() ;
        for(int i = 1 ; i <= n ; i ++) d[i] = read() ;
        for(int i = 1 ; i <= n ; i ++) v[i] = read() ;
        fac[0] = 1 ;
        for(int i = 1 ; i <= 7 ; i ++) fac[i] = fac[i - 1] * i ;
        for(int i = 1 ; i <= n ; i ++)
            for(int S = 1 ; S <= fac[7] ; S ++) {
            	Split(S) ;
            	for(int j = 1 , ret ; j <= 8 ; j ++) { // ö¾ÙµÚi+1λµÄ˳Ðò 
            	    ret = 0 ;
                    for(int k = 1 ; k <= 7 ; k ++)
            	        if(p[k] < j) w[k] = p[k] ;
            	        else w[k] = p[k] + 1 ;
            	    w[8] = j ;
            	    for(int k = 1 ; k <= 7 ; k ++)
            	        if((i - (7 - k)) > 0 && w[k] < w[8] && d[i - (7 - k)] >= 8 - k)
            	            ret += v[i - (7 - k)] ;
            	    for(int k = 1 ; k <= 7 ; k ++)
            	        if((i - (7 - k)) > 0 && w[k] > w[8] && d[i + 1] >= 8 - k)
            	            ret += v[i + 1] ;
            	    for(int k = 2 ; k <= 8 ; k ++)
            	        if(w[k] > w[1]) w[k] -- ;
            	    for(int k = 1 ; k <= 7 ; k ++)
            	        w[k] = w[k + 1] ;
            	    int x = Merge() ;
            	    f[i + 1][x] = max(f[i + 1][x] , f[i][S] + ret) ;
                }
            }
        for(int i = 1 ; i <= fac[7] ; i ++) Ans = max(Ans , f[n][i]) ;
        printf("%d
    ",Ans) ;
        return 0 ;
    }
    
  • 相关阅读:
    Photoshop CC 与前端那些事
    gulp入門指南
    谈谈css左右等高的几个方法
    angularjs给Model添加拦截过滤器,路由增加限制,实现用户登录状态判断
    前端自动化工具
    React Router
    Sublime Text 3 常用插件安装
    c++ primer学习指导(13)--1.6书店程序
    c++ primer学习指导(12)--1.5.2初识成员函数
    c++ primer学习指导(11)--1.5.1Sales_item类
  • 原文地址:https://www.cnblogs.com/beretty/p/9851504.html
Copyright © 2020-2023  润新知