BZOJ1071 [SCOI2007]压缩 其他

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ1071


题意概括

  有两个序列a[1..n], b[1..n],其编号为1..n,设为s序列。现在我们要求出最长的满足条件的s的子序列s',设va=min(a[s[i]]), vb=min(b[s[i]]), 满足对于所有的j=s'[i], A*(a[j]-va)+B*(b[j]-vb)<=C。


 

题解

  设v[i]=A*a[i]+B*b[i];
  那么,要求满足v[s'[i]]-A*va-B*vb<=C,
  移项得:v[s[i]]<=A*va+B*vb+C
  于是我们可以按照两种顺序排序,一个是v,一个是b。
  那么如果确定鼓励va,则:
  A*a[i]+B*b[i]<=A*va+B*vb+C
  而A*a[i]>=A*va
  所以B*b[i]<=B*vb+C
  移项B*(b[i]-vb)<=C,
  b[i]<=vb+C/B,
  都是整数,所以可以直接取整。
  所以,对于所有的b[i],有vb<=b[i]<=vb+C/B。
  然后双指针,一个扫按照b排序的,一个扫按照s排序的。


 

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
typedef long long LL;
const int N=5000+5;
struct Player{
    LL a,b,v;
}v[N],a[N];
int n;
LL A,B,C;
bool cmp_v(Player a,Player b){
    return a.v<b.v;
}
bool cmp_a(Player a,Player b){
    return a.a<b.a;
}
int main(){
    scanf("%d%lld%lld%lld",&n,&A,&B,&C);
    for (int i=1;i<=n;i++){
        scanf("%lld%lld",&v[i].a,&v[i].b);
        v[i].v=A*v[i].a+B*v[i].b;
        a[i]=v[i];
    }
    sort(v+1,v+n+1,cmp_v);
    sort(a+1,a+n+1,cmp_a);
    int ans=0;
    for (int i=1;i<=n;i++){
        int L=0,R=0,cnt=0;
        LL xL=a[i].b,xR=xL+C/B;
        LL va,vb=xL;
        for (int j=1;j<=n;j++){
            va=a[j].a;
            while (R<n&&v[R+1].v<=A*va+B*vb+C){
                R++;
                if (xL<=v[R].b&&v[R].b<=xR)
                    cnt++;
            }
            while (L<n&&a[L+1].a<va){
                L++;
                if (xL<=a[L].b&&a[L].b<=xR)
                    cnt--;
            }
            ans=max(ans,cnt);
        }
    }
    printf("%d",ans);
    return 0;
}

  

posted @   zzd233  阅读(239)  评论(0编辑  收藏  举报
努力加载评论中...

点击右上角即可分享
微信分享提示