zoukankan      html  css  js  c++  java
  • 2018-04-26 模拟考试 答题报告

    【留坑待填】...

     

      一.任务分配

    Description

    图书馆按顺序排列有N本书需要维护,每本书的总页数不一定相同。现有M位员工。可以给每个员工分配连续的一段书籍,让他进行维护。现在的问题是,怎么样分配,工作任务最重(需要维护的页数最多)的人维护的页数尽量少。

    Input

    第一行两个数,N、M。接下来N行,每行一个整数,表示一本书的页数。

    Output

    任务最重的人最少需要维护的页数。

    Sample Input 1

    5 3
    3
    2
    4
    1
    5
    

    Sample Output 1

    5

    Hint

    对于10%的数据,N<=10

    对于30%的数据,N<=10^4

    对于100%的数据,N<=10^5,M<=N。

    一本书的页数最多10^4。

    老师说这次全是dp, 我还真的信了555...;

    这tm显然是二分啊, 做过了三次了不说了;

    代码 :

    //By zZhBr
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define int long long
    
    int n, m;
    
    int a[100010];
    
    int sum, lss;
    
    bool check(int x)
    {
        int non = 0;
        int lst = 0;
        for(register int i = 1 ; i <= n ; i ++)
        {
            lst += a[i];
            if(lst > x)
            {
                non++;
            //    printf("mid == %d, lst == %d, non == %d
    ",x, lst, non);
                lst = 0;
                i = i - 1;
            //    continue;
            }     
        }
        if(lst != 0) non++;
        //printf("mid == %d, non == %d
    ", x, non);
        if(non > m) return 1;
        else return 0;
        
    }
    
    signed main()
    {
        cin >> n >> m;
        
        for(register int i = 1 ; i <= n ; i ++) 
        {
            scanf("%lld", &a[i]);
            sum += a[i];
            lss = max(lss, a[i]);
        }
        
        if(m >= n)
        {
            int ans = 0;
            for(register int i = 1 ; i <= n ; i ++)
            {
                ans = max(ans, a[i]);
            }
            cout << ans << endl;
            return 0;
        }
        
        int l = lss, r = sum , mid;
    
        while(l < r)
        {
            int mid = l + r >> 1;
        //    cout << mid << endl;
            bool f = check(mid);
            if(f)
            {
                l = mid + 1;
            }
            else
            {
                r = mid;
            }
        }
        
        cout << l << endl;
        return 0;
        
        
        
    }
    zZhBr

    水!

    二.吃夜宵

    Description

    众所周知,pb是个长相好,身材好,人品好的三好少年,他每个月都要拿出很多的零花钱来孝敬父母、孝敬老师等等。所以这个月他的荷包终于顶不住了!这天晚上,当他和室友去吃夜宵时,看到那么多喷香的夜宵,他恨不得每样都吃一遍,但是他的经济情况已经不允许了。但是第二天就是发工资的日子,所以他决定今朝有酒今朝醉,把所有的钱都花掉! 一共有n样夜宵,每样都有一个价格Vi,pb每样夜宵最多买一样!他一共有C元钱,因为他想尽量多吃点夜宵,所以当他买完夜宵后,剩余的钱一定不够再买任何一样其他的夜宵了。他想知道一共有多少种买法,好来看看哪种买法最合算。

    Input

    第一行一个数T,表示一共T组数据。每组数据第一行两个数N,C。接下来一行N 个数,表示N种夜宵的价格。

    Output

    输出T行,每行第一个数为数据编号,然后是买法总数。

    Sample Input 1

    1
    6 25
    8 9 8 7 16 5
    

    Sample Output 1

    1 15

    Hint

    对10%的数据,N<=10, C<=200

    对20%的数据,C<=1000

    T<=10 , N <= 30 , C <= 10000

    这题明显背包!

    然而我没做出来。

    可以看这个代码666: %%%YoungNeal 

    这个坑填不了;

    算了留下我的辣鸡10分代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <bitset>
    using namespace std;
    #define LL long long
    
    int T, n, m;
    
    int a[35];
    
    
    int main()
    {
        cin >> T;
        for(register int time = 1 ; time <= T ; time ++)
        {
            scanf("%d%d", &n, &m);
            
            for(register int i = 1 ; i <= n ; i ++)
            {
                scanf("%d", &a[i]);
            }
            
            sort(a + 1, a + 1 + n);
            
            //    LL f[(1<<n)+1];
            //    memset(f, 0, sizeof f);
                
                LL e = 1 << n;
                LL cnt = 0;
                for(register LL i = 0 ; i <= e ; i ++)
                {
                    LL my = 0;
                    bool flag = 0;
                    
                    for(register int j = 1 ; j <= n ; j ++)
                    {
                        if(i & (1 << (j - 1)))
                        {
                            my += a[j];
                        }
                        if(my > m) 
                        {
                            goto End;
                        }
                    }
    
                    
                    
                        for(register int j = 1 ; j <= n ; j ++)
                        {
                            if(i & (1 << (j - 1))) continue;
                            if(my + a[j] <= m) goto End;
                            else if(my + a[j] > m) break;
                        }
                    
                    cnt++;
                //    printf("status : %d, money : %d, cnt : %d
    ", i, my, cnt);
                    End:;
                    
                }
                
                printf("%d %lld
    ", time, cnt);
                continue;
            
            
            
        }
        return 0;
    }
    zZhBr

     经过一下午的挣扎加上te神犇的指导, 终于A了这道题;

    下面说说思路;

    先进行一波排序;

    设dp[i] [j], 表示对于第i个数, 0 ~ i的数必须选, i+1这个数必须不选, i+2~n的数可选可不选;

    我们为什么要这么设? 因为我们发现,要保证最后的结果不能买任何东西, 我们就要知道我们所没有选的最廉价的物品是什么;

    因为我们从小到大排了序, 就保证了i+1是我们所没有选择的最小的数;(机智)!

    这样定义的话, 我们就把这个问题分成了n+1个阶段, 每个阶段互不干扰, 便于最后求和, 棒棒的!

    我们首先先求出排序后序列的前缀和, 然后进行第一波转移(其实是初始化) : dp[i] [m-sum[i]] = 1;(m - sum[i] >= 0);

    如果a[1] > m 直接退出byby。

    然后从0开始枚举i;为什么从0开始枚举? 因为保证枚举到所有的状态, 当i == 0的时候的状态也是独立的一个状态;

    第二维枚举j : i + 2 ->n, 为什么要从i+2开始?因为我们保证了i+1不选, 而我们要从i+2到n中选择所有可以选择的数进行转移;

    第三维枚举p值, 从0到m - a[i], 为什么不是从m-a[i]到0? 因为, 我们要保证每一个数只选择一次,如果从后往前转移的话, 我们就不能保证这个数只选择了一次;

    枚举所有可能的情况求和;ok。

    代码奉上:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    #define int long long
    
    int T, n, m;
    int a[10010];
    int dp[35][10010];
    int sum[10010];
    
    signed main()
    {
        cin >> T;
        for(register int time = 1 ; time <= T ; time ++)
        {
            memset(dp, 0, sizeof dp);
            memset(sum, 0, sizeof sum);
            scanf("%lld%lld", &n, &m);
            
            for(register int i = 1 ; i <= n ; i ++) 
            {
                scanf("%lld", &a[i]);
            }
            
            sort(a + 1, a + 1 + n);
            
            if(a[1] > m)
            {
                printf("%d 0
    ", time);
                continue;
            }
            
        //    a[n+1] = m;
            
            for(register int i = 1 ; i <= n ; i ++)
            {
                sum[i] = sum[i-1] + a[i];
            }
            
            dp[0][m] = 1;
            
            for(register int i = 0 ; i <= n ; i ++)
            {
                if(m - sum[i] >= 0)
                {
                    dp[i][m-sum[i]] = 1;
                    //printf("dp[0][%d] == %d 
     ",m-sum[i],dp[0][m-sum[i]]);
                } 
                
            }
            
            for(register int i = 0 ; i <= n ; i ++) 
            {
                for(register int j = i + 2 ; j <= n ; j ++)
                {
                    for(register int p = 0 ; p + a[j] <= m ; p ++)
                    {
                        dp[i][p] += dp[i][p+a[j]]; 
                    //    if(dp[i][p]!=0)printf("dp[%d][%d]=%d
    ",i,p,dp[i][p]);
                    }
                    //cout << endl;
                }
            }
            
            
            
            int ans = 0;
            
            for(register int i = 0 ; i <= n ; i ++)
            {
                for(register int j = 0 ; j < a[i+1] ; j ++)
                {
                    ans += dp[i][j];
                }
            }
            
            printf("%lld %lld
    ", time , ans);
        }
        return 0;
    }
    zZhBr

    三.货车运输

    (待添加)...

  • 相关阅读:
    最小生成树之prim算法
    洛谷P1443 马的遍历【BFS】
    (四)学习CSS之position、bottom、left、right和top属性
    (三)学习CSS之opacity 属性
    (二)学习CSS之cursor属性
    (一)学习CSS之z-index属性
    (八)学习MVC之三级联动
    (七)学习MVC之CodeFirst迁移更新数据库
    (六)学习MVC之标签a提交页面
    (四)学习MVC之修改个人资料和身份验证登陆
  • 原文地址:https://www.cnblogs.com/BriMon/p/8952030.html
Copyright © 2011-2022 走看看