zerojudge i164. 比對卡片(進階版)

題目在 https://zerojudge.tw/ShowProblem?problemid=i164

這題是要根據老師的卡片的位置找出學生相同的卡片的最近距離. 寫出對的程式不難, 難的是測資#9一直TLE. 我原以為演算法已經夠快了, 怎麼會TLE呢? 後來終於想到如果是下面這種測資, 沒有用快速的搜尋, 就會變成非常非常慢.

100000
1 1 1 1 1 1.......1 
1 1 1 1 1 1.......1
這種情況解決後, 就AC了. 記得要用 scanf和printf 還可以比cin,cout省個200ms左右. 
資料結構

我把學生的資料放在RECORD裡, 裡面就是一個vector, 用來應付很多相同編號的卡片時, 需要儲存很多的index. vector在增加後面資料的速度很快,正好適用.
class RECORD {
	public:
		vector <int> INDEX;
		void Set(int index){
			INDEX.push_back(index);
		}
};


RECORD student[100001];
int teacher[100000];
C++

演算法

輸入學生資料時, 卡片編號是I, 就把index加入RECORD[I]的INDEX裡, 這樣也不用再排序student[ ], 找卡片編號的資料時也快.

for(int i=0;i<N;i++){
		int I;
		scanf("%d", &I);
		student[I].Set(i);
	}
C++

最後就是根據老師的卡片編號, 去學生的student[ ]裡找最接近的位置.

int target=teacher[i];
int C=student[target].INDEX.size();
if(C==0){  //沒有紀錄
        printf("-1 ");
}else{
	auto p1= student[target].INDEX.begin();
	auto p2= student[target].INDEX.end();
	auto lower = std::lower_bound(p1, p2 , i); //找大於或等於i的
	int diff1=1000000;
	int diff2=1000000;
	if(lower != p2){  //有找到
		diff1=*lower - i;
	}
	if(lower != p1){ //如果不是第一個
		lower--;    //找前一個
		diff2=i - *lower;
	}

	printf("%d ",(diff1<diff2? diff1:diff2)); //誰比較小就印出誰
}
C++

完整程式如下.

#include <vector>
#include <iostream>
using namespace std;

class RECORD {
	public:
		vector <int> INDEX;
		void Set(int index){
			INDEX.push_back(index);
		}
};


RECORD student[100001];
int teacher[100000];

int main() {

	cout.sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	int N;
	scanf("%d", &N);
	for(int i=0;i<N;i++){
		scanf("%d", &teacher[i]);
	}

	for(int i=0;i<N;i++){
		int I;
		scanf("%d", &I);
		student[I].Set(i);
	}

	for(int i=0;i<N;i++){
	        int target=teacher[i];
		int C=student[target].INDEX.size();
		if(C==0){  //沒有紀錄
			printf("-1 ");
		}else{
			auto p1= student[target].INDEX.begin();
			auto p2= student[target].INDEX.end();
			auto lower = std::lower_bound(p1, p2 , i); //找大於或等於i的
			int diff1=1000000;
			int diff2=1000000;
			if(lower != p2){  //有找到
				diff1=*lower - i;
			}
			if(lower != p1){ //如果不是第一個
				lower--;    //找前一個
				diff2=i - *lower;
			}

			printf("%d ",(diff1<diff2? diff1:diff2)); //誰比較小就印出誰
		}
	}
	return 0;
}
C++