Eating Plan

Eating Plan

2019南昌G

模数为合数,所以只有约3000个数字不为0

记录一下不为0的数字位置

H[x]代表距离为x的连续段的数字和的最大值

处理出H[x]

再H[x] = max(H[x],H[x-1])记录下前缀最大,

对每个询问二分答案

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,q;
int A[3004];
const int mod = 998857459;
void init()
{
    A[0]=1;
    for(int i=1;i<=3000;i++){
        A[i]=(A[i-1]*i)%mod;
    }
}
int x;
vector<int>v;
int B[100005];
int H[100005];
int pre[3005];
signed main()
{
    init();
    scanf("%lld%lld",&n,&q);
    v.push_back(0);
    for(int i=1;i<=n;i++){
         scanf("%lld",&x);
        if(x<=3000){
            B[i]=A[x];
            v.push_back(i);
        }else{
            B[i]=0;
        }
    }
    
    for(int j=1;j<v.size();j++){
       pre[j]=(B[v[j]]+pre[j-1])%mod;
    }
    for(int i=1;i<=v.size();i++){
        for(int j=0;j+i-1<v.size();j++){
            H[v[j+i-1]-v[j]+1]=max(H[v[j+i-1]-v[j]+1],(pre[j+i-1]-pre[j-1]+mod)%mod);
        }
    }
    for(int i=1;i<=n;i++){
        H[i]=max(H[i],H[i-1]);
    }
    for(int i=1;i<=q;i++){
        scanf("%lld",&x);
        int l = 1,r =n+1;
        while(l+1<=r){
            int mid=(l+r)/2;
            if(H[mid]<x){
                l= mid+1;
            }else r=mid;
        }
        if(l==n+1){
            cout<<-1<<'
';
        }else{
            cout<<l<<'
';
        }
    }
}
原文地址:https://www.cnblogs.com/liulex/p/12015129.html