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

    三.货车运输

    (待添加)...

  • 相关阅读:
    HDU 1800 Flying to the Mars 字典树,STL中的map ,哈希树
    字典树 HDU 1075 What Are You Talking About
    字典树 HDU 1251 统计难题
    最小生成树prim算法 POJ2031
    POJ 1287 Networking 最小生成树
    次小生成树 POJ 2728
    最短路N题Tram SPFA
    poj2236 并查集
    POJ 1611并查集
    Number Sequence
  • 原文地址:https://www.cnblogs.com/BriMon/p/8952030.html
Copyright © 2011-2022 走看看