完美K倍子數組詳解

剛剛提交成功這道題,趕緊來寫個博客,以便記錄和分享!
題目:
時間限制:10000ms
單點時限:1000ms
內存限制:256MB
描述
如果一個數組滿足長度至少是2,並且其中任意兩個不同的元素Ai和Aj (i ≠ j)其和Ai+Aj都是K的倍數,我們就稱該數組是 完美K倍數組。
現在給定一個包含N個整數的數組A = [A1, A2, … AN]以及一個整數K,請你找出A的最長的完美子數組B,輸出B的長度。
如果這樣的子數組不存在,輸出-1。
輸入
第一行包含兩個整數N和K。
第二行包含N個整數A1, A2, … AN。
1 ≤ N ≤ 100000
1 ≤ Ai, K ≤ 1000000000
輸出
一個整數,表示答案。
樣例輸入
5 3
1 3 2 3 6
樣例輸出
3

害,你們瞅瞅這題目敘述的可真是多,真是讓人頭大!
在這裏插入圖片描述
那我就來簡單說一下題目的意思吧!
意思是:就是在給的數組中重新分離出一個數組,讓這個新數組的任意兩個數之和是K的倍數!
比如數組爲{1,3,2,3,6},K=3, 則新數組應該是{3,3,6}
思路:1.K是奇數,則只有這個新數組中全是K的倍數的數,纔是完美的
2.K是偶數,則除了新的數組全是K的倍數情況,還有一種是任意兩個餘數是K/2數的和也是K的倍數。
3.如果這個數組中沒有K的倍數的數,則考慮兩個數之和是K,而這種情況下,數組長度只能是2.

1.的話肯定不用說,都理解。
對2.舉一個例子,K=4,數組{8,4,2,6,10}
則最大長度應該是3,數組是{2,6,10}
3.K=4,數組{1,3,2,2,1} 長度是2
可以是{1,3}或{2,2}但長度都是2

下面來代碼:
1

.#include<iostream>
#include<cstdlib>
#include<set>
using namespace std;
int main()
{
    set<int>mod;
    int n,b,x;
    long int k;
    cin>>n>>k;
    int a[100000];
    int i,j,s=0,sum=0,flag=0;
    for(i=0;i<n;i++)
    {
        cin>>a[i];
        if(a[i]%k==0)//如果k爲奇數,則只有當數組中全爲k的倍數時才滿足完美k倍子數組要求,當然k爲偶數此情況也滿足要求
        {
            s++;
        }
       if(k%2==0)//如果k爲偶數,則任意兩個餘數是k/2的數的和也是k的倍數
        {
            if(a[i]%k==k/2.0)
            {
                sum++;
            }
        }
      if(a[i]%k!=0)  //數組中沒有k的倍數的數,則兩個數相加爲k倍的數,且數組長度只能爲2
        {
            x=a[i]%k;
            if(mod.find(k-x)!=mod.end())
            {
               flag=1;
            }
            mod.insert(x);     
        }
    }
    b=max(s,sum);
        if(b<=1)
        {
            if(flag) cout<<"2";
            else cout<<"-1";
        }
    else cout<<b;
    return 0;
}

      
      

2.下面這個是發帖時一個大哥的代碼,我也寫在這,以供大家參考,學習!

// 完美K倍子數組

/*
1. 統計所有K的倍數的數, 個數 n1
2. 如果K是偶數, 統計所有餘數是 K/2 的數, 個數 n2
上述n1和n2的最大值, 如果大於等於2,則就是結果。
3.否則查找是否有兩個數相加等於K的倍數, 找到則結果是2, 否則結果失敗

注意: 檢測兩個數相加,如果直接用雙重循環,會超時, 需要優化算法.
*/
#include <iostream>
#include <set>
using namespace std;
// 統計K的倍數數量
int TotalK(int data[], int N, int K)
{
	// 倍數
	int n1 = 0;
	for (int i = 0; i < N; i++)
	{
		if (data[i] % K == 0)
		{
			++n1;
		}
	}
	return n1;
}

// 統計K/2
int TotalK_2(int data[], int N, int K)
{
	if (K % 2 != 0)//k是奇數,則返回,因爲這裏是判斷兩個k/2的數相加是k
	{
		return 0;
	}

	int n2 = 0;
	int K_2 = K / 2;
	for (int i = 0; i < N; i++)
	{
		if (data[i] % K == K_2)
		{
			++n2;
		}
	}

	return n2;
}

// 測試兩數之和
bool TestSumK(int data[], int N, int K)
{
	set<int> test; // 餘數

	for (int i = 0; i < N; ++i)
	{
		int d1 = data[i] % K;
		int d2 = K - d1;
		if (test.find(d2) != test.end())
		{
			// 找到
			return true;
		}
		test.insert(d1);
	}

	return false;
}

int main()
{
	int N, K;
	cin>>N>>K;
	int* data = new int[N];
	for (int i = 0; i < N; i++)
	{
	 cin >> data[i];
	}
	// 全部數組
	/*if (K == 1)
	{
		cout<<N<<endl;
		return 0;
	}*/

	// 倍數
	int n1 = TotalK(data, N, K);
	// 餘數 N/2
	int n2 = TotalK_2(data, N, K);
	int n1_n2 = (n1 >= n2 ? n1 : n2);
	if (n1_n2 >= 2) {
		cout<<n1_n2<<endl;
		return 0;
	}
	// 查找兩個數相加等於K的倍數
	bool test = TestSumK(data, N, K);
	if (test)
	{
		cout<<2<<endl;
		return 0;
	}
	// 失敗
	cout<<-1<<endl;

	return 0;
}

注:這裏用到了**set函數的.find()**的用法,所以在這裏說一下
find() ,返回給定值值得定位器,如果沒找到則返回end()。

#include <iostream>
 #include <set>
 using namespace std;
 int main()
{
 int a[] = {1,2,3};
set<int> s(a,a+3);
  set<int>::iterator iter;
  if((iter = s.find(2)) != s.end())
  {
    cout<<*iter<<endl;
  }
  return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章