2022年2月1日 星期二

Uva 11536: Smallest Sub-Array

解題心得

參考網路解法才寫出來。

這題似乎要用到two pointer的概念的變化題。

先假設用一個queue來記錄所有sequence中1~k數字的index,以及countk紀錄當下蒐集到1~k中的總共幾個數字,跟一個array來記錄i最後出現的位置。

每次遇到1~k數字,就先丟進queue中。接著檢查是否第一次遇到這個數字(有沒有在queue中,也就是有沒有在highlight起來的範圍內),若沒有,則更新countk。最後,我們要檢查highlight範圍左側是不是要變化了,判斷方法是看範圍內的最左側,若去掉該位置,依然能保有1~k的數字,那就可以放棄,一直重覆到不能為止。

那又要怎麼確保會找到最短長度呢?首先我們知道當countk==k時就是一組解,而我們的解法是從頭到尾掃過一次並且動態更新,那麼只要每次都檢查當前的解是否更小即可。

另外我在比較cpe提供的參考解法與網路其他人解法時,一開始不懂為何countk只要++,不考慮--的情況。這是因為只有一開始才是還沒找到解的狀態,只要一找到符合的解,只會不斷解查是不是要更新邊界,但也會確保始終是保持1~k數字的區間。

程式碼 

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

int seq[1000001] = { 1,2,3 };

int main()
{
	int T;
	cin >> T;
	for (int round = 1; round <= T; round++)
	{
		int n, m, k;
		cin >> n >> m >> k;

		for (int i = 3; i < n; i++)
			seq[i] = (seq[i - 1] + seq[i - 2] + seq[i - 3]) % m + 1;

		queue<int> q;
		int countK = 0, last_pos[101] = { 0 }, ans = 1000001;
		for (int i = 0; i < 101; i++) last_pos[i] = -1;
		for (int i = 0; i < n; i++)
		{
			if (seq[i] <= k)
			{
				q.push(i);
				if (last_pos[seq[i]] == -1) countK++;
				last_pos[seq[i]] = i;

				while (q.front() != last_pos[seq[q.front()]])
					q.pop();
				if (countK == k)
					ans = min(ans, i - q.front() + 1);
			}
		}
		cout << "Case " << round << ": ";
		if (ans == 1000001) cout << "sequence nai" << endl;
		else cout << ans << endl;
	}
	return 0;
}

沒有留言:

張貼留言