枚举暴力一发就行。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>
using namespace std;
int n,m;
int main()
{
while (cin>>n>>m)
{
int ans=1100000;
for (int i=1;i<=m;i++)
{
int a,b;
cin>>a>>b;
int d=n/a;
if (n%a) d++;
ans=min(ans,d*b);
}
cout<<ans<<endl;
}
return 0;
}
首先我们很容易知道,题目无解当且仅当 ∑h[i]<W∗H 。对于一段长为 W 的序列,高度小于 H 部分的高度和为 ∑h[i](h[i]<H) ,高度大于 H 部分的高度和为 ∑h[i](h[i]>H) ,而最小的移动数应为 max(∑h[i](h[i]<H),∑h[i](h[i]>H)) 。然后我们线性扫一遍就行了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>
using namespace std;
typedef long long LL;
LL n,w,h;
LL sum,a[151000];
LL ans;
LL l,r;
LL cal()
{
LL res=l+r-min(l,r);
return res;
}
int main()
{
while (scanf("%I64d %I64d %I64d",&n,&w,&h)==3)
{
sum=0;
memset(a,0,sizeof(a));
for (int i=1;i<=n;i++)
scanf("%I64d",&a[i+w]),sum+=a[i+w];
if (sum<w*h)
{
printf("-1\n");
continue;
}
l=0,r=0;
for (int i=1;i<=w;i++)
{
if (a[i]<h) l+=h-a[i];
else r+=a[i]-h;
}
ans=cal();
for (int i=1;i<=w+n;i++)
{
if (a[i]<h) l-=h-a[i];
else r-=a[i]-h;
if (a[i+w]<h) l+=h-a[i+w];
else r+=a[i+w]-h;
ans=min(ans,cal());
}
printf("%I64d\n",ans);
}
return 0;
}
判断无解的方法与上题相同。考虑一段序列,不难发现,使它移动次数最少的高度应为整个序列的平均高度(同时还得比 H 高)。由于平均高度不一定为整数,所以我们还得考虑取整后+1这一高度。上题由于高度确定,所以可以 O(1) 维护两部分和的值,而此题不确定,所以我们需要利用树状数组来维护这一部分的和。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>
using namespace std;
typedef long long LL;
const int maxn=60000;
LL nu[maxn+10];
LL height[maxn+10];
const LL INF=1e18;
inline int lowbit(int x)
{
return (x&-x);
}
void add(LL *fenwick,int x,LL value)
{
for (int i=x;i<=maxn;i+=lowbit(i))
fenwick[i]+=value;
}
LL get(LL *fenwick,int x)
{
LL sum=0;
for (int i=x;i;i-=lowbit(i))
sum+=fenwick[i];
return sum;
}
LL nowh;
int n;
LL h,w;
LL v[3*maxn+10];
LL ansx,ans,sum;
void check(LL x)
{
if (x<h||x*w>sum) return;
LL minn=x*get(nu,x-1)-get(height,x-1),maxx=get(height,55001)-get(height,x)-x*(get(nu,55001)-get(nu,x));
LL res=max(minn,maxx);
if (res<ans||((res==ans)&&(x>ansx)))
{
ans=res;
ansx=x;
}
}
int main()
{
while (scanf("%d %I64d %I64d",&n,&w,&h)==3)
{
memset(nu,0,sizeof(nu));
memset(height,0,sizeof(height));
for (int i=0;i<3*maxn+10;i++)
v[i]=1;
sum=0;
h++;
for (int i=1;i<=n;i++)
scanf("%I64d",&v[i+maxn]),++v[i+maxn],sum+=v[i+maxn];
if (sum<w*h)
{
printf("-1\n");
continue;
}
nowh=w;
add(nu,1,w);
add(height,1,w);
ans=INF;
ansx=0;
for (int i=maxn+1;i<=n+maxn+w;i++)
{
nowh-=v[i-w];
add(nu,v[i-w],-1);
add(height,v[i-w],-v[i-w]);
nowh+=v[i];
add(nu,v[i],1);
add(height,v[i],v[i]);
LL x=nowh/w;
check(x);
check(x+1);
check(h);
}
if (ans==INF) printf("-1\n");
else printf("%I64d %I64d\n",ansx-1,ans);
}
return 0;
}
静态的逆序对我们可以用树状数组维护,由于此题中有插入和删除操作,会改变相对位置,所以需要利用数据结构套数据结构的方式。由于此题可以 O(nn−−√) 搞,所以我们就用块状链表套树状数组实现。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>
using namespace std;
const int maxn=21000;
inline int lowbit(int x)
{
return (x&-x);
}
void add(int *fenwick,int x,int value)
{
for (int i=x;i<=maxn;i+=lowbit(i))
fenwick[i]+=value;
}
int get(int *fenwick,int x)
{
int sum=0;
for (int i=x;i;i-=lowbit(i))
sum+=fenwick[i];
return sum;
}
const int m=350;
struct data
{
int s,a[2*m+5];
int c[21000];
data *next;
data()
{
memset(c,0,sizeof(c));
next=NULL;
}
};
data *root;
void insert(int x,int pos)
{
if (root==NULL)
{
root=new(data);
root->s=1;
root->a[1]=x;
add(root->c,x,1);
return ;
}
data *k=root;
while (pos>k->s && k->next!=NULL)
{
pos-=k->s;
k=k->next;
}
memmove(k->a+pos+1,k->a+pos,sizeof(int)*(k->s-pos+1));
k->s++;
k->a[pos]=x;
add(k->c,x,1);
if (k->s==2*m)
{
data *t=new(data);
t->next=k->next;
k->next=t;
memcpy(t->a+1,k->a+m+1,sizeof(int)*m);
for (int i=1;i<=m;i++)
{
add(k->c,t->a[i],-1);
add(t->c,t->a[i],1);
}
t->s=k->s=m;
}
}
void del(int pos)
{
data *k=root;
while (pos>k->s && k->next!=NULL)
{
pos-=k->s;
k=k->next;
}
add(k->c,k->a[pos],-1);
memmove(k->a+pos,k->a+pos+1,sizeof(int)*(k->s-pos));
k->s--;
}
int find(int pos)
{
data *k=root;
while (pos>k->s && k->next!=NULL)
{
pos-=k->s;
k=k->next;
}
return (k->a[pos]);
}
void destroy(data *k)
{
if (k->next!=NULL)
destroy(k->next);
delete(k);
}
int cal(int pos)
{
int res=0;
data *k=root;
int x=find(pos);
while (pos>k->s && k->next!=NULL)
{
pos-=k->s;
res+=get(k->c,20000)-get(k->c,x);
k=k->next;
}
for (int i=1;i<pos;i++)
if (k->a[i]>x) res++;
for (int i=pos+1;i<=k->s;i++)
if (k->a[i]<x) res++;
while (k->next!=NULL)
{
k=k->next;
res+=get(k->c,x-1)-get(k->c,0);
}
return res;
}
int ans;
int n,q;
int main()
{
while (scanf("%d %d",&n,&q)==2)
{
root=NULL;
ans=0;
for (int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
insert(x,i);
ans+=cal(i);
}
for (int i=1;i<=q;i++)
{
int op;
scanf("%d",&op);
if (op==0)
{
int x,y;
scanf("%d %d",&x,&y);
x++;
insert(y,x);
ans+=cal(x);
}
else
{
int x;
scanf("%d",&x);
ans-=cal(x);
del(x);
}
printf("%d\n",ans);
}
destroy(root);
}
return 0;
}