题面:https://www.cnblogs.com/Juve/articles/11534880.html
A:
T可以写成如下形式:$T=b^k*S+m*a$,
其中$m=\sum\limits_{i=1}^{k}p_i*b^i$
然后k最多64,所以枚举即可
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #define int long long #define re register using namespace std; int s,t,a,b,ans=0x7fffffff,res,tot=0,n=1; signed main(){ scanf("%lld%lld%lld%lld",&s,&t,&a,&b); while(t-s*n>=0){ re int p=t-s*n; if(p%a==0){ p/=a; res=0; for(re int i=tot;i>=0;--i){ int q=pow(b,i); res+=p/q; p%=q; } ans=min(res+tot,ans); } n*=b; ++tot; } printf("%lld\n",ans); return 0; }
C:
有一个贪心策略
对于每一个点,我们找能加热到它的加热器中右端点最大的一个,然后加热
如果没有符合的就用特殊加热器
如果扫到当前点它已经加热超过p了就跳过
然后有一个部分分算法
如果p很小,我们可以枚举特殊加热器的使用次数,提前给他们加热,然后用贪心策略解决
之后我们优化贪心
我们发现预先枚举的使用特殊加热器的次数所得到的答案具有单谷性质,所以我们可以三分
修改操作用差分和树状数组即可
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #define int long long #define re register using namespace std; const int MAXN=1e5+5; int n,m,t,p[MAXN],maxx=0,ans,g[MAXN],c[MAXN],l,r; struct node{ int l,r; friend bool operator < (node a,node b){ return a.l==b.l?a.r<b.r:a.l<b.l; } }pos[MAXN]; int lowbit(int x){ return x&-x; } int update(int x,int val){ while(x<=n){ c[x]+=val; x+=lowbit(x); } } int query(int x){ int res=0; while(x>0){ res+=c[x]; x-=lowbit(x); } return res; } int check(int k){ int res=k*t; for(int i=1;i<=n;++i) c[i]=0; for(int i=1;i<=n;++i){ int q=query(i); if(q+k>=p[i]) continue; if(g[i]==0||g[i]>n){ return -0x7fffffffffffffff; }else{ int tim=p[i]-q-k; res+=tim; update(i,tim); update(g[i]+1,-tim); } } return -res; } signed main(){ scanf("%lld%lld%lld",&n,&m,&t); for(int i=1;i<=n;++i){ scanf("%lld",&p[i]); maxx=max(maxx,p[i]); } for(int i=1;i<=m;++i) scanf("%lld%lld",&pos[i].l,&pos[i].r); sort(pos+1,pos+m+1); int j=1,mx=0; for(int i=1;i<=n;++i){ if(mx<i) mx=0; while(j<=m&&pos[j].l<=i) mx=max(mx,pos[j++].r); g[i]=mx; } l=0,r=maxx; while(r-l>2){ int lmid=(l+r)>>1; int rmid=lmid+1; if(check(lmid)<=check(rmid)) l=lmid; else r=rmid; } ans=min(min(-check(l),-check(r)),-check(l+1)); printf("%lld\n",ans); return 0; }