1. 程式人生 > >hdu 2430 Beans

hdu 2430 Beans

題意:題目大意:有n坨豌豆,每坨都有w[i]個,現在要從中選擇連續的若干坨,然後用一個能裝p個豌豆的揹包裝豆子,直到剩下的豌豆數量<=p為止,還要求剩下的豌豆數量少於k,問最多能裝多少包。-------引自ZeroClock

題解:

1.目標是求(sum[i] - sum[j](i != j)) % p <= k && 使得sum[i] - sum[j]最大

2.變形-----(sum[i] % p - sum[j] % p + p) % p <= k

3.然後我們可以按sum[i] % p,給陣列排序。

4.用單調佇列分情況討論解決這個問題了

5.hint:因為存在某堆有0個bean的情況,需要在排序的時候特殊處理

總結:

1.這道題又是看到zeroclock說需要把式子變形之後才知道怎麼寫的。

2.當沒有方向的時候,應該嘗試著對公式進行小小的變形,貌似在這種地方栽過好幾次跟頭了

3.最近依舊學習opencv,幾乎把書從頭到尾的讀了一遍,發現確實應該抓住重點看書,看急需瞭解的知識,對於不會

需要延伸的知識,再去有目的的查資料,這樣效率更高!

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
#define MAXN 1000005
int n,p,k;
struct Node
{
    ll s;
    bool operator < (const Node & a)const{
        if(s % p == a.s % p)return s < a.s;
        return s % p < a.s % p;
    }
}node[MAXN];
ll deque[MAXN];
int main()
{
    int _;
    for(int kcas = scanf("%d",&_);kcas <= _;kcas++)
    {
        scanf("%d%d%d",&n,&p,&k);
        bool success = false;
        for(int i = 1;i <= n;i++)
        {
            scanf("%I64d",&node[i].s);
            if(node[i].s == 0)success = true;
            node[i].s += node[i - 1].s;
        }
        sort(node,node + n + 1);
        ll maxn = 0,ans = 0;
        int tail = 0,head = 0;
        for(int i = 1,j = 0;i <= n;i++)
        {
            while(tail != head && deque[tail - 1] > node[i - 1].s)
                tail--;
            deque[tail++] = node[i - 1].s;
            while(tail != head && deque[head] % p + k < node[i].s % p)
                head++;
            if(head != tail)ans = max(ans,node[i].s - deque[head]);

            while(j < i && node[j].s % p + p - node[i].s % p <= k)
            {
                maxn = max(maxn,node[j].s);
                j++;
            }
            ans = max(ans,maxn - node[i].s);
        }
        if(!ans && !success)printf("Case %d: -1\n",kcas);
        else printf("Case %d: %I64d\n",kcas,ans / p);
    }
}