算法优化专题

题目

A - Stars POJ - 2352
Astronomers often examine star maps where stars are represented by points on a plane and each star has Cartesian coordinates. Let the level of a star be an amount of the stars that are not higher and not to the right of the given star. Astronomers want to know the distribution of the levels of the stars.

For example, look at the map shown on the figure above. Level of the star number 5 is equal to 3 (it’s formed by three stars with a numbers 1, 2 and 4). And the levels of the stars numbered by 2 and 4 are 1. At this map there are only one star of the level 0, two stars of the level 1, one star of the level 2, and one star of the level 3.

You are to write a program that will count the amounts of the stars of each level on a given map.
Input
The first line of the input file contains a number of stars N (1<=N<=15000). The following N lines describe coordinates of stars (two integers X and Y per line separated by a space, 0<=X,Y<=32000). There can be only one star at one point of the plane. Stars are listed in ascending order of Y coordinate. Stars with equal Y coordinates are listed in ascending order of X coordinate.
Output
The output should contain N lines, one number per line. The first line contains amount of stars of the level 0, the second does amount of stars of the level 1 and so on, the last line contains amount of stars of the level N-1.
Sample Input
5
1 1
5 1
7 1
3 3
5 5
Sample Output
1
2
1
1
0
Hint
This problem has huge input data,use scanf() instead of cin to read data to avoid time limit exceed.

分析

对每个星星,求x和y坐标都小于自己的星星个数
题目输入已经保证了y坐标升序
每次输入一个星星的坐标,只要找之前输入的星星x坐标比自己小的有几个
用一个数组bit [i],表示x坐标为 i 的星星个数
也就是说,每次找bit数组 0~x的前缀和
可以用树状数组来动态维护这个前缀和
注意x坐标可能为0,而lowbit运算中0会造成死循环
所以x坐标为0时单独处理,不参与前缀和
也可以直接x++,把所有x坐标都右移一个单位,不会影响前缀和

代码

#include
using namespace std ;
#include

const int MAX_N=2e4+10;
const int MAX_X=32000+10;
int bit[MAX_X];		//存x坐标为i的星星个数
int level[MAX_N];
int N;

void add(int x,int y){	
	//if(x==0) return ; 	//题目x坐标可以为0 但lowbit运算中0会死循环
	
	for(;x<=MAX_X;x+=x&-x) bit[x]+=y;	
}

int sum(int x){
	int s=0;
	for(;x>0;x-=x&-x) s+=bit[x];	
	return s;
}

int main()
{
	cin>>N; 
	int x,y; 
	for(int i=1;i<=N;i++){	
		cin>>x>>y;
		//cout<<"level "<
		
		//x++; 				//直接 x++ 所有x右移一单位 不影响前缀和 
		level[sum(x)+bit[0]]++;		
		if(x) add(x,1);
		else bit[0]++; 		//0单独处理即可 不参与前缀和	 
	}
	
	for(int i=0;i<=N-1;i++) cout<<level[i]<<endl;
	
	
	return 0;
}

题目

F - Expedition POJ - 2431
A group of cows grabbed a truck and ventured on an expedition deep into the jungle. Being rather poor drivers, the cows unfortunately managed to run over a rock and puncture the truck’s fuel tank. The truck now leaks one unit of fuel every unit of distance it travels.

To repair the truck, the cows need to drive to the nearest town (no more than 1,000,000 units distant) down a long, winding road. On this road, between the town and the current location of the truck, there are N (1 <= N <= 10,000) fuel stops where the cows can stop to acquire additional fuel (1…100 units at each stop).

The jungle is a dangerous place for humans and is especially dangerous for cows. Therefore, the cows want to make the minimum possible number of stops for fuel on the way to the town. Fortunately, the capacity of the fuel tank on their truck is so large that there is effectively no limit to the amount of fuel it can hold. The truck is currently L units away from the town and has P units of fuel (1 <= P <= 1,000,000).

Determine the minimum number of stops needed to reach the town, or if the cows cannot reach the town at all.
Input

  • Line 1: A single integer, N

  • Lines 2…N+1: Each line contains two space-separated integers describing a fuel stop: The first integer is the distance from the town to the stop; the second is the amount of fuel available at that stop.

  • Line N+2: Two space-separated integers, L and P
    Output

  • Line 1: A single integer giving the minimum number of fuel stops necessary to reach the town. If it is not possible to reach the town, output -1.
    Sample Input
    4
    4 4
    5 2
    11 5
    15 10
    25 10
    Sample Output
    2
    Hint
    INPUT DETAILS:

The truck is 25 units away from the town; the truck has 10 units of fuel. Along the road, there are 4 fuel stops at distances 4, 5, 11, and 15 from the town (so these are initially at distances 21, 20, 14, and 10 from the truck). These fuel stops can supply up to 4, 2, 5, and 10 units of fuel, respectively.

OUTPUT DETAILS:

Drive 10 units, stop to acquire 10 more units of fuel, drive 4 more units, stop to acquire 5 more units of fuel, then drive to the town.

分析

贪心 要使加油次数最少
我们可以每次行驶到没油时 再决定去哪个加油站加油
这样我们就可以每次选择已经经过的加油站中加油量最多的
用优先队列,每经过一个加油站,就把它的加油量入队
然后每次取出加油量的最大值,直到油足够到达下一个加油站

代码

#include
using namespace std;
#include
#include

const int MAX_N=1e4+5;
struct stop{
	//int d;	//起点到加油站距离 
	int l;	//终点到加油站距离 
	int fuel;	//可供油量 	
}a[MAX_N];

bool cmp(stop a,stop b){
	return a.l>b.l;		//离终点远 离起点近
}

int main()
{
	int N,L,P; cin>>N;
	for(int i=0;i<N;i++) cin>>a[i].l>>a[i].fuel; 
	cin>>L>>P;
	
	sort(a,a+N,cmp);
	priority_queue<int> pque;
	
	int ok=0,ans=0;
	a[N].l=0; a[N].fuel=0; 
	
	for(int i=0;i<=N;i++){//为了简便  终点也算进加油站 
		
		int d=L-a[i].l; 
		if(P<d) 
			while(P<d){	
				
				if(pque.empty()) { cout<<"-1"<<endl; return 0; }//情况2 加油过程中没油了 
				
				P+=pque.top();  pque.pop();	
				ans++;
			}
		if(P>=L) { ok=1; break; }
		pque.push(a[i].fuel);
		
	}
	
	if(ok)cout<<ans<<endl;
	else cout<<"-1"<<endl;	
	
	
	return 0;
 } 

题目

G - Sliding Window POJ - 2823
An array of size n ≤ 10 6 is given to you. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves rightwards by one position. Following is an example:
The array is [1 3 -1 -3 5 3 6 7], and k is 3.
Window position Minimum value Maximum value
[1 3 -1] -3 5 3 6 7 -1 3
1 [3 -1 -3] 5 3 6 7 -3 3
1 3 [-1 -3 5] 3 6 7 -3 5
1 3 -1 [-3 5 3] 6 7 -3 5
1 3 -1 -3 [5 3 6] 7 3 6
1 3 -1 -3 5 [3 6 7] 3 7
Your task is to determine the maximum and minimum values in the sliding window at each position.

Input
The input consists of two lines. The first line contains two integers n and k which are the lengths of the array and the sliding window. There are n integers in the second line.
Output
There are two lines in the output. The first line gives the minimum values in the window at each position, from left to right, respectively. The second line gives the maximum values.
Sample Input
8 3
1 3 -1 -3 5 3 6 7
Sample Output
-1 -3 -3 -3 3 3
3 3 5 5 6 7

分析

模拟一下窗口移动,我们可以发现
当一个较小的数 进入这个窗口时,窗口内比它大的数都不可能再被输出了,所以我们可以把比它大的数都丢掉
这样每次进入一个数,都把比他大的数丢掉,这个序列一定是递增的
所以我们可以用单调队列维护这个递增序列

先k-1个全部入队,然后从第k个开始,每进一个输出一个
并且为了判断队首什么时候出队
也就是最小的数什么时候会被移出窗口
让每个数在数组a中的下标 i 入队
队首与队尾的下标差 和窗口长度作比较

代码

#include
using namespace std;
#include

const int INF=2e9;
const int MAX_N=1e6+10;	
int que[MAX_N];	
int a[MAX_N];

int main()
{
	int n,k; 	
	scanf("%d %d",&n,&k);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	if(k==1){
		for(int i=1;i<=n;i++) printf("%d ",a[i]); printf("\n");
		for(int i=1;i<=n;i++) printf("%d ",a[i]); printf("\n");
		return 0;
	}
	
	que[0]=0; a[0]=-INF;
	
	int l=1,r=0;			
	//if(k==1) que[++r]=1; 
	for(int i=1;i<=k-1;i++){	//先k-1个入队		 
		if(a[que[r]] <a[i]) que[++r]=i;
		
		else{
			while(a[que[r]] >a[i] && r>=l) r--;
			que[++r]=i;
		} 
	}
	
	for(int i=k;i<=n;i++){	//第k个开始 进一个 输出一个 
		
		if(i-que[l]==k) l++;	//区间长度超过 k个时  队首出队 
		
		if(a[que[r]] <a[i]) que[++r]=i; 
		else{
			while(a[que[r]] >a[i] && r>=l) r--;
			que[++r]=i;
		} 
		printf("%d ",a[que[l]]);
	}
	printf("\n");
	
	 
//*******以下维护递减序列 
	que[0]=0; a[0]=INF;
	
	l=1,r=0;
	for(int i=1;i<=k-1;i++){			 
		if(a[que[r]] >a[i]) que[++r]=i;
		
		else{
			while(a[que[r]] <a[i] && r>=l) r--;
			que[++r]=i;
		} 
	}
	
	for(int i=k;i<=n;i++){	
		
		if(i-que[l]==k) l++;	
		
		if(a[que[r]] >a[i]) que[++r]=i; 
		else{
			while(a[que[r]] <a[i] && r>=l) r--;	
			que[++r]=i;
		} 
		printf("%d ",a[que[l]]);
	}
	printf("\n");
	
	
	return 0;
}

题目

分析

代码



题目

分析

代码



你可能感兴趣的:(算法优化专题)