hdu 6444 - 最大子段和(单调队列)

题目链接:点击这里

 

解题思路:

根据k我们会得到一个循环周期,将在同一个循环节的点都归为同一类,因为归为同一类的点走过一个循环周期得到的快乐值时一样的。

很明显如果循环周期是负的那一定就不走一个循环了。那直接求最长不超过m的最大连续子段和就行了。

如果循环周期大于0,就有两种可能了(循环周期次数a=m/len(len为周期长度),b=m%n):

1.走完a圈后再加上不超过b的最大连续字段和

2.走完a-1圈后再加上不超过len的最大连续字段和,因为刚好走完一圈不一定会比走了一部分多,加上一圈反而会使最大值变少。

 

#include
using namespace std;
#define fi first
#define se second
#define lowbit(x) x&(-x)
const int mod = 1e9+7;
const int mx =  1e5+5;
typedef long long ll;
ll n,m,k,s;
bool vis[mx];
vectorg[mx];
ll sum[mx];
ll a[mx];
ll q[mx];
ll l,r;
void del(ll k,ll m){
    while(lm)l++;
}
void ins(ll k){
    while(l=sum[k]) r--;
    q[r++] = k;
}
ll getans(ll i,ll k){
    int n = g[i].size();
    for(int j = 1; j <= n; j++)
        sum[j] = g[i][j-1],sum[j] += sum[j-1];
    for(int i = 1; i <= n; i++)
        sum[i+n] = sum[n]+sum[i];
    for(int i = 1; i <= n; i++)
        sum[i+2*n] = sum[2*n]+sum[i];
    l = r = 0;
    ll ans = 0;
    ins(0);
    for(int i = 1; i <= 3*n; i++){
        del(i,k);
        if(ans=1)
                op += len;//把最后一圈加进去考虑走完一圈还是不走那个大
            if(op==0){
                ans = max(ans,tmp);
                continue;
            }
            ans = max(ans,tmp+getans(i,op));
        }
        printf("Case #%d: %lld\n",ca++,max(0ll,s-ans));
    }
    return 0;
}

 

你可能感兴趣的:(单调性)