HDU 2430 Beans (单调队列+公式化简)
题意:给你n袋豆子,每袋都有w[i]个豆子,接着任选连续任意个袋子的豆子合在一起放入容量为p的多个袋子里(每个袋子必须放满),问剩余的豆子数<=k时,能放满最多的袋子的个数
题解:个数与p都比较大,直接模拟O(n^2),余数处理(dp)O(n*p)都会超时。
我们可以首先抽象出一个公式来:设前缀和为sum[i],则我们求(j+1,i)的豆子的数量时会使用sum[i]-sum[j]来求,而我们需要求的就是max(sum[i]-sum[j]),条件的是
(sum[i]-sum[j])%P<=k ——> (sum[i]%p-sum[j]%p+p)%p<=k
分类讨论:当sum[i]%p>=sum[j]%p 时就是 sum[i]%p-k <= sum[j]%p <= sum[i]%p
当sum[i]%p<sum[j]%p我们可以反向来看转化为上面的情况
则我们枚举sum[i]时就只需要求出最前面一个满足条件的sum[j]就好(因为w[i]非负)
这样我们找到前缀和求余数数组rem,首先第一关键字rem升序第二关键字下标升序,接着我们枚举rem[现在]时就一定满足rem[现在]>=rem[队首],而rem[现在]-k是非递减的,所以我们可以单调队列来优化,队列里面rem从小到大,当 rem[现在]-k>rem[队首]则出队,最后rem[现在]入队(rem[现在]一定不小于队尾的rem)并向前走到比现在小的下标就好
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector> #include<string> #include<cstdio> #include<cstring> #include<stdlib.h> #include<iostream> #include<algorithm> using namespace std; #define eps 1E-8 /*注意可能会有输出-0.000*/ #define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型 #define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化 #define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0 #define mul(a,b) (a<<b) #define dir(a,b) (a>>b) typedef long long ll; typedef unsigned long long ull; const int Inf=1<<28; const double Pi=acos(-1.0); const int Mod=1e9+7; const int Max=1000100; int que[Max];//单调队列 struct node { int rem;//前缀余数 ll pre;//前缀和 int pos; }res[Max]; bool cmp(struct node p1,struct node p2) { if(p1.rem==p2.rem) return p1.pos<p2.pos; return p1.rem<p2.rem;//排序关键 } ll nmax(ll a,ll b) { return a>b?a:b; } ll Solve(int n,int p,int k) { ll ans=-1ll; int top=0,bot=0; que[top++]=0; for(int i=1;i<=n;++i)//遍历x%p 找最小下标 { while(top>bot&&res[i].rem-k>res[que[bot]].rem)//小于这个值的出队(因为之后这个值会变大) bot++; if(top>bot) ans=nmax(ans,(res[i].pre-res[que[bot]].pre)/(ll)p); while(top>bot&&res[que[bot]].pos>res[i].pos)//单调队列维护下标最小 bot++; que[top++]=i; } return ans; } int main() { int t,n,p,k,num,coun=0; scanf("%d",&t); while(t--) { scanf("%d %d %d",&n,&p,&k); res[0].rem=0,res[0].pre=0ll,res[0].pos=0;//注意加一个 for(int i=1;i<=n;++i) { scanf("%d",&num); res[i].pre=res[i-1].pre+num; res[i].rem=res[i].pre%p; res[i].pos=i; } sort(res+1,res+n+1,cmp); printf("Case %d: %I64d\n",++coun,Solve(n,p,k)); } return 0; }
分类:
ACM_数据结构
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决