Description
FJ有M个牛棚,编号1至M,刚开始所有牛棚都是空的。FJ有N头牛,编号1至N,这N头牛按照编号从小到大依次排队走进牛棚,每一天只有一头奶牛走进牛棚。第i头奶牛选择走进第p[i]个牛棚。由于奶牛是群体动物,所以每当一头奶牛x进入牛棚y之后,牛棚y里的所有奶牛们都会喊一声“欢迎欢迎,热烈欢迎”,由于声音很大,所以产生噪音,产生噪音的大小等于该牛棚里所有奶牛(包括刚进去的奶牛x在内)的数量。FJ很讨厌噪音,所以FJ决定最多可以使用K次“清空”操作,每次“清空”操作就是选择一个牛棚,把该牛棚里所有奶牛都清理出去,那些奶牛永远消失。“清空”操作只能在噪音产生后执行。现在的问题是:FJ应该选择如何执行“清空”操作,才能使得所有奶牛进入牛棚后所产生的噪音总和最小?
Input
第一行,N、M、K。
接下来有N行,每行一个整数,第i行是p[i]。
Output
最小的噪音总和。
Sample Input
输入1:
5 1 2
1
1
1
1
1
输入2:
11 2 3
1
2
1
2
1
2
1
2
1
2
1
Sample Output
输出1:
7
样例解释1:
第1头奶牛进入牛棚且产生噪音后,“清空”牛棚。第3头奶牛进入牛棚且产生噪音后,再次“清空”牛棚。5头奶牛产生的噪音依次是:1,1,2,1,2。如果没有“清空”操作,5头奶牛产生的噪音依次是:1,2,3,4,5。
输出2:
18
样例解释2:
第3头奶牛进入牛棚1且产生噪音后,“清空”牛棚1。第7头奶牛进入牛棚1且产生噪音后,“清空”牛棚1。
第6头奶牛进入牛棚2且产生噪音后,“清空”牛棚2。
Data Constraint
对于40%的数据,M=1。
对于60%的数据,1<=N <= 1000。
对于80%的数据,1<=N <= 50000。
对于100%数据, 1<=N <= 1000000, 1<=M<=100, 1<=K<= 500。
Solutoin
对于每一个牛棚是独立的。可以预处理出第i个牛棚用j次的代价,那么问题转化为将k次操作分给i个牛棚,每次操作对应着i的一个值,求最大代价。
那么直接dp,设f[i][j]表示前i个牛棚一共用了j次,则f[i][j]=min{ f [ i-1 ][ j-k ]+cost [ i-1 ][ k ]}
时间O(mk^2)。
实际上可以优化到k log m。
用堆维护所有牛棚中哪一个多用一次贡献最大(做差),一共取k次,即k log m。
Code1
#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define ll long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define N 1000010
using namespace std;
I rd(I &x){
x=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
}
I n,m,k,x,t[110];
ll f[110][510],g[110][510],ans=(ll)1e12,y,r;
I main(){
rd(n),rd(m),rd(k);
F(i,1,n){
rd(x);
t[x]++;
if(t[x]==1) t[0]++;
}
F(i,1,100) if(!t[i]){
F(j,i+1,100) if(t[j]){
t[i]=t[j],t[j]=0;break;
}
}
F(i,1,t[0]){
F(j,0,k){
y=t[i]/(j+1),r=t[i]%(j+1);
f[i][j]=(ll)r*((2+y)*(y+1)/2)+(ll)(j+1-r)*((y+1)*y/2);
}
}
mem(g,0x3f);
F(i,0,k) g[1][i]=f[1][i];
F(i,2,t[0]){
F(j,0,k){
F(l,0,j) if(g[i-1][j-l]+f[i][l]>=0) g[i][j]=min(g[i][j],g[i-1][j-l]+f[i][l]);
}
}
F(i,1,k) g[t[0]][i]=min(g[t[0]][i],g[t[0]][i-1]);
printf("%lld\n",g[t[0]][k]);
return 0;
}
Code2
#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define ll long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define N 1000010
#define M 110
using namespace std;
I rd(I &x){
x=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
}
I n,m,k,x,d[M*4],c[M];
ll ans,a[M],b[M],t[M];
ll ask(I x,I y){
ll p=x/y,r=x%y;
return (ll)r*((2+p)*(p+1)/2)+(ll)(y-r)*((p+1)*p/2);
}
ll calc(I x){return a[d[x]]-b[d[x]];}
void down(I x){
I y=x<<1;
while(y<=d[0]&&calc(y)>calc(x)||y+1<=d[0]&&calc(y+1)>calc(x)){
y+=(calc(y)<calc(y+1));
swap(d[x],d[y]);
x=y;y=x<<1;
}
}
void up(I x){
while(x>1&&calc(x)>calc(x>>1)){swap(d[x],d[x>>1]);x>>=1;}
}
void ins(I x){
d[++d[0]]=x;
up(d[0]);
}
I main(){
rd(n),rd(m),rd(k);
F(i,1,n){
rd(x);
t[x]++;
}
F(i,1,m) if(t[i]){
a[i]=(t[i]+1)*t[i]/2;
b[i]=ask(t[i],c[i]=2);
ins(i);ans+=a[i];
}
F(i,1,k){
ans-=a[d[1]]-b[d[1]];
a[d[1]]=b[d[1]],b[d[1]]=ask(t[d[1]],++c[d[1]]);
down(1);
}
printf("%lld\n",ans);
return 0;
}
作者:zsjzliziyang
QQ:1634151125
转载及修改请注明
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/103499662