A B C
略
D
思路
数据范围比较小,直接爆搜+剪枝。
剪枝1:如果当前攻击的次数大于等于已知的最小次数,得到的答案一定不会更优。
剪枝2:考虑攻击第个时,必须要把第个打死,因为之后不管怎么攻击都不会再对第个造成影响。所以攻击次数从开始枚举(如果一直打第个,那么第个被攻击在次后死亡,如果第个在开始攻击前就已经死亡,就从开始枚举)。
代码
#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define sf(a) scanf("%lld",&(a));
#define pf(a) printf("%lld\n",(a));
typedef long long ll;
using namespace std;
const ll N=20,INF=0x3f3f3f3f;
ll a,b,n,ans=INF;
ll h[N],rec[1000],hit[N];
void dfs(ll cur,ll tot)
{
if(tot>=ans)
return;
if(cur==n)
{
rep(i,1,n)
if(h[i]>=0)
return;
ans=tot;
ll p=0;
rep(i,1,n)
rep(j,1,hit[i])
rec[++p]=i;
return;
}
ll cnt=0;
int i=max(0ll,(h[cur-1]+b)/b);
while(h[cur-1]>=0 || h[cur+1]>=0 || h[cur]>=0)
{
if(cnt<i)
{
h[cur]-=(i-cnt)*a;
h[cur-1]-=(i-cnt)*b;
h[cur+1]-=(i-cnt)*b;
cnt=i;
}
hit[cur]=cnt;
dfs(cur+1,tot+cnt);
++i;
}
hit[cur]=0;
h[cur]+=cnt*a;
h[cur-1]+=cnt*b;
h[cur+1]+=cnt*b;
}
int main()
{
cin>>n>>a>>b;
rep(i,1,n)
cin>>h[i];
dfs(2,0);
cout<<ans<<endl;
rep(i,1,ans)
cout<<rec[i]<<" ";
cout<<endl;
}
E
思路
首先想到的是枚举每一个区间,用区间最大值和区间最小值之差满足题意的区间维护答案。复杂度。
一步步优化,首先区间最大值和最小值可以通过线段树来维护查询,因为本题没有修改操作,所以ST表也可以。使用线段树每次查询的复杂度为,总的复杂度降为。
当区间左端点确定时,区间最大值和最小值的差满足单调性,也就是随着右端点右移,这个差会不变或变大,但一定不可能变小。所以用二分来优化确定右端点的过程,复杂度降为。
代码
#include<bits/stdc++.h>
#define lc p<<1
#define rc p<<1|1
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define sf(a) scanf("%lld",&(a));
#define pf(a) printf("%lld\n",(a));
#define __ <<" "<<
#define pii pair<ll,ll>
typedef long long ll;
using namespace std;
const ll N=1E5+10,INF=0x3f3f3f3f;
ll n,k,ans,cnt;
ll a[N],ma[4*N],mi[4*N],c[4*N];
pii rec[N];
void update(int p)
{
ma[p]=max(ma[lc],ma[rc]);
mi[p]=min(mi[lc],mi[rc]);
c[p]=ma[p]-mi[p];
}
void build(int p,int l,int r)
{
if(l==r)
{
ma[p]=a[l];
mi[p]=a[l];
c[p]=0;
return;
}
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
update(p);
}
pii query(int p,int l,int r,int al,int ar)
{
if(al<=l && ar>=r)
return make_pair(ma[p],mi[p]);
int mid=(l+r)>>1;
pii ret=make_pair(-INF,INF);
if(al<=mid)
{
pii tmp=query(lc,l,mid,al,ar);
ret.first=max(ret.first,tmp.first);
ret.second=min(ret.second,tmp.second);
}
if(ar>mid)
{
pii tmp=query(rc,mid+1,r,al,ar);
ret.first=max(ret.first,tmp.first);
ret.second=min(ret.second,tmp.second);
}
return ret;
}
int main()
{
sf(n)
sf(k)
rep(i,1,n)
sf(a[i]);
build(1,1,n);
#ifdef tst
while(1)
{
int x,y;
cin>>x>>y;
cout<<query(1,1,n,x,y)<<endl;
}
#endif
#ifndef tst
rep(i,1,n)
{
ll l=i,r=n;
while(l<=r)
{
int mid=(l+r)>>1;
pii que=query(1,1,n,i,mid);
if(que.first-que.second>k)
r=mid-1;
else
l=mid+1;
}
--l;
ll dis=l-i+1;
if(dis>ans)
{
ans=dis;
rec[cnt=1]=make_pair(i,l);
}
else if(dis==ans)
rec[++cnt]=make_pair(i,l);
}
cout<<ans __ cnt<<endl;
rep(i,1,cnt)
cout<<rec[i].first __ rec[i].second<<endl;
#endif
}