25482: Beauty
时间限制: 1 Sec 内存限制: 128 MB
献花: 7 解决: 3
[献花][花圈][TK题库]题目描述
一年一度的星哥选美又拉开了帷幕
N个人报名参加选拔,每个人都有着各自的相貌参数和身材参数(不大于10000的正整数)。你的任务是尽可能让更多人被星哥选中,而唯一要求就是,在这只队伍里面的每个人,都需满足以下不等式:
A (H−h)+B(W−w)≤C
其中H和W为这个人的相貌和身材,h和w为选中者中的最小相貌参数和最小身材参数,而A、B、C为三个不大于10000的正的整型常数。
现在请计算星哥最多可以选中多少人。
输入
第一行:一个整数:N
第二行:三个分开的整数:A,B和C
第三行到第N+2行:每行有两个用空格分开的整数,分别表示一个人的相貌参数和身材参数
输出
第一行:最多被选的人数
样例输入
8 1 2 4 5 1 3 2 2 3 2 1 7 2 6 4 5 1 4 3样例输出
5提示
第1,2,3,4,7号可以组成一支符合要求的队伍,没有更大的队伍了
这道题第一眼看成离散化然而发现数据范围不大并不需要离散化OwO
对于这题似乎有两种解法, 一种是 $O(n^2log(n))$ 的, 还有一种似乎是 $O(n*w_{max})$ 的. 根据某dalao $wq$ 所言还能用 $CDQ$ 分治水过去w.
这里只讲第二种好了w实际评测中发现时间消耗比第一种少 $30\%$ 左右
首先枚举 $h$, 然后在内层枚举要处理的结点, 这样我们可以得到 $h$ $H$ $W$ 三个值. 结合 $A$ $B$ $C$ 与不等式我们可以计算出要使该要处理的结点被选中所需的最小 $w$ 值. 然后再根据 $W$ 值可以计算出要使该结点要被选中, $w$ 所应当落在的区间. 然后我们在数组中对区间进行差分, 计算完对于某个 $h$ 的所有结点的 $w$ 区间后对差分所得数组求前缀和处理出对于每个 $w$ 值有多少个结点被选中. 然后根据结点信息枚举可能的 $w$ 并对最终结果取 $max$. 对于所有 $n$ 个 $h$ 都计算一下, 然后全局最大值即为最优解.
其中要注意的是: 由于我们所枚举的 $h$ 是最小值, 所以对于 $H$ 值小于我们所枚举的 $h$ 的结点应直接跳过防止影响答案. 而由于 $w$ 是最小值, 则 $B(W-w) \geq 0$ , 所以 $A(H-h) \leq C$ , 所以对于 $A(H-h) > C$ 的情况我们也要直接跳过防止影响答案.
参考代码如下:
GitHub
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <iostream> 6 #include <algorithm> 7 8 const int MAXN=1510; 9 10 struct Point{ 11 int x; 12 int y; 13 Point(int x=0,int y=0){ 14 this->x=x; 15 this->y=y; 16 } 17 }; 18 19 int n; 20 int m; 21 int l=0,r=0; 22 int xa,ya,xb,yb; 23 Point q[30000100]; 24 int dis[MAXN][MAXN]; 25 int melt[MAXN][MAXN]; 26 bool visited[MAXN][MAXN]; 27 28 void BFS(); 29 void gch(char&); 30 void Initialize(); 31 void SPFA(int,int); 32 33 int main(){ 34 Initialize(); 35 BFS(); 36 SPFA(xa,ya); 37 printf("%d\n",dis[xb][yb]); 38 return 0; 39 } 40 41 void SPFA(int x,int y){ 42 memset(visited,0,sizeof(visited)); 43 dis[x][y]=0; 44 q[r++]=(Point(x,y)); 45 visited[x][y]=true; 46 while(l<r){ 47 x=q[l].x; 48 y=q[l].y; 49 l++; 50 visited[x][y]=false; 51 if(x>1&&dis[x][y]<dis[x-1][y]&&dis[x-1][y]!=melt[x-1][y]){ 52 dis[x-1][y]=std::max(dis[x][y],melt[x-1][y]); 53 if(!visited[x-1][y]){ 54 visited[x-1][y]=true; 55 q[r++]=(Point(x-1,y)); 56 } 57 } 58 if(x<n&&dis[x][y]<dis[x+1][y]&&dis[x+1][y]!=melt[x+1][y]){ 59 dis[x+1][y]=std::max(dis[x][y],melt[x+1][y]); 60 if(!visited[x+1][y]){ 61 visited[x+1][y]=true; 62 q[r++]=(Point(x+1,y)); 63 } 64 } 65 if(y>1&&dis[x][y]<dis[x][y-1]&&dis[x][y-1]!=melt[x][y-1]){ 66 dis[x][y-1]=std::max(dis[x][y],melt[x][y-1]); 67 if(!visited[x][y-1]){ 68 visited[x][y-1]=true; 69 q[r++]=(Point(x,y-1)); 70 } 71 } 72 if(y<m&&dis[x][y]<dis[x][y+1]&&dis[x][y+1]!=melt[x][y+1]){ 73 dis[x][y+1]=std::max(dis[x][y],melt[x][y+1]); 74 if(!visited[x][y+1]){ 75 visited[x][y+1]=true; 76 q[r++]=(Point(x,y+1)); 77 } 78 } 79 } 80 } 81 82 void BFS(){ 83 memset(visited,0,sizeof(visited)); 84 while(l<r){ 85 int x=q[l].x; 86 int y=q[l].y; 87 ++l; 88 if(x>1&&!visited[x-1][y]&&melt[x][y]+1<melt[x-1][y]){ 89 melt[x-1][y]=melt[x][y]+1; 90 visited[x-1][y]=true; 91 q[r++]=(Point(x-1,y)); 92 } 93 if(x<n&&!visited[x+1][y]&&melt[x][y]+1<melt[x+1][y]){ 94 melt[x+1][y]=melt[x][y]+1; 95 visited[x+1][y]=true; 96 q[r++]=(Point(x+1,y)); 97 } 98 if(y>1&&!visited[x][y-1]&&melt[x][y]+1<melt[x][y-1]){ 99 melt[x][y-1]=melt[x][y]+1; 100 visited[x][y-1]=true; 101 q[r++]=(Point(x,y-1)); 102 } 103 if(y<m&&!visited[x][y+1]&&melt[x][y]+1<melt[x][y+1]){ 104 melt[x][y+1]=melt[x][y]+1; 105 visited[x][y+1]=true; 106 q[r++]=(Point(x,y+1)); 107 } 108 } 109 } 110 111 void Initialize(){ 112 char ch; 113 memset(dis,0x3F,sizeof(dis)); 114 memset(melt,0x3F,sizeof(melt)); 115 scanf("%d%d",&n,&m); 116 for(int i=1;i<=n;i++){ 117 for(int j=1;j<=m;j++){ 118 gch(ch); 119 if(ch==‘.‘){ 120 q[r++]=(Point(i,j)); 121 melt[i][j]=0; 122 visited[i][j]=true; 123 } 124 else if(ch==‘L‘){ 125 q[r++]=(Point(i,j)); 126 melt[i][j]=0; 127 visited[i][j]=true; 128 if(xa==0){ 129 xa=i; 130 ya=j; 131 } 132 else{ 133 xb=i; 134 yb=j; 135 } 136 } 137 } 138 } 139 } 140 141 void gch(char& target){ 142 do{ 143 target=getchar(); 144 }while(target!=‘.‘&&target!=‘X‘&&target!=‘L‘); 145 }
Backup
以及日常图包w