【UOJ386】【UNR #3】鴿子固定器 鏈表
阿新 • • 發佈:2018-07-13
\n class 次方 print 維護 刪掉 sca clu reverse 個。
題目描述
有 \(n\) 個物品,每個物品有兩個屬性:權值 \(v\) 和大小 \(s\)。
你要選出 \(m\) 個物品,使得你選出的物品的權值的和的 \(d_v\) 減掉大小的極差的 \(d_s\) 次方最大。
\(n\leq 200000,m\leq 50,1\leq d_v,d_s\leq 2\)
題解
如果選的物品的數量不到 \(m\) 個,且不連續,那麽一定不是最優的。
因為如果不是連續的,那麽可以多選一個大小在這些物品之間的物品,使答案更優。
如果選了 \(m\) 個物品,那麽可以枚舉權值最小的物品 \(i\),可以發現,選的物品的大小組成了一個包含 \(i\) 的區間。這樣的區間最多只有 \(O(m)\)
否則可以刪掉 \(i\) 這個物品,換上一個權值更大的物品,使答案更優。
可以用一個鏈表維護物品的大小組成的序列。
時間復雜度:\(O(nm)\)
題解
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N=200010; int l[N],r[N]; int n,m,ds,dv; ll s[N]; ll fp(ll a,int b) { return b==1?a:a*a; } ll calc(ll x,ll y) { return fp(x,dv)-fp(y,ds); } void del(int x) { r[l[x]]=r[x]; l[r[x]]=l[x]; } struct pp { int s,v,c; }; pp a[N],b[N],c[N]; int cmp1(pp a,pp b) { return a.s<b.s; } int cmp2(pp a,pp b) { return a.v<b.v; } int t; ll ans; int main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif scanf("%d%d%d%d",&n,&m,&ds,&dv); for(int i=1;i<=n;i++) scanf("%d%d",&a[i].s,&a[i].v); sort(a+1,a+n+1,cmp1); for(int i=1;i<=n;i++) { a[i].c=i; b[i]=a[i]; } for(int i=m;i<=n;i++) { ll temp=0; for(int j=i-m+1;j<=i;j++) { temp+=a[j].v; ans=max(ans,calc(temp,a[j].s-a[i-m+1].s)); } } sort(a+1,a+n+1,cmp2); for(int i=0;i<=n;i++) r[i]=i+1; for(int i=1;i<=n+1;i++) l[i]=i-1; for(int i=1;i<=n;i++) { t=0; for(int j=a[i].c,k=1;j>=1&&k<=m;j=l[j],k++) c[++t]=b[j]; reverse(c+1,c+t+1); for(int j=r[a[i].c],k=2;j<=n&&k<=m;j=r[j],k++) c[++t]=b[j]; for(int j=1;j<=t;j++) s[j]=s[j-1]+c[j].v; for(int j=m;j<=t;j++) ans=max(ans,calc(s[j]-s[j-m],c[j].s-c[j-m+1].s)); del(a[i].c); } printf("%lld\n",ans); return 0; }
【UOJ386】【UNR #3】鴿子固定器 鏈表