1. 程式人生 > 實用技巧 >倍數問題(2018藍橋杯)

倍數問題(2018藍橋杯)

題目描述:

眾所周知,小蔥同學擅長計算,尤其擅長計算一個數是否是另外一個數的倍數。
但小蔥只擅長兩個數的情況,當有很多個數之後就會比較苦惱。
現在小蔥給了你 n 個數,希望你從這 n 個數中找到三個數,使得這三個數的和是 K 的倍數,且這個和最大。資料保證一定有解。

輸入格式:

從標準輸入讀入資料。

第一行包括 2 個正整數 n, K。
第二行 n 個正整數,代表給定的 n 個數。

輸出格式:

輸出到標準輸出。
輸出一行一個整數代表所求的和。

示例:

輸入:
4 3
1 2 3 4

輸出:
9

資料約定:

對於 30% 的資料,n <= 100。
對於 60% 的資料,n <= 1000
。 對於另外 20% 的資料,K <= 10。 對於 100% 的資料,1 <= n <= 10^5, 1 <= K <= 10^3,給定的 n 個數均不超過 10^8。 資源約定: 峰值記憶體消耗(含虛擬機器) < 256M CPU消耗 < 1000ms 請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。 注意: main函式需要返回0; 只使用ANSI C/ANSI C++ 標準; 不要呼叫依賴於編譯環境或作業系統的特殊函式。 所有依賴的函式必須明確地在原始檔中 #include <xxx> 不能通過工程設定而省略常用標頭檔案。

題目分析:

本題可以使用暴力列舉,列舉分析所有的數,若分析得出結果值最大值輸出;

但是若純 暴力時間複雜度將會變得十分大,

所以可以先分析所有資料,只保留餘數相同的最大的三個數。然後逐個列舉得出結果。

程式碼:

c++:

#pragma warning(disable:4996)
#include<iostream>
#include<memory>
#include<vector>
#include<unordered_map>
typedef long long ll;
inline int read()
{
    int x = 0
, f = 1; char ch = getchar(); while (ch < '0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } int main() { int i, num; int k, flag = 1; int b[1001][3];//用於判斷餘數相同的三個數 memset(b, -1, sizeof(b)); std::unordered_map<int, int>c;//map的key值存放餘數,value值存放餘數對應二維陣列b的下標 scanf("%d %d", &i, &num); while (i--) { k = read(); int kk = k % num; if (!c[kk]) { c[k % num] = flag;//將餘數所在的位置給map的對映 b[flag][0] = k; flag++; } else//若該餘數有值,則替換其中最小值或者加入其中 { int inte = k; for (int z = 0;z < 3;z++) if (b[c[kk]][z] < inte) inte ^= b[c[kk]][z] ^= inte ^= b[c[kk]][z]; } } //列舉 ll ans = 0, v1, v2, v3; for (auto iter1 = c.begin();iter1 != c.end();iter1++) { for (auto iter2 = c.begin();iter2 != c.end();iter2++) { int mainder = (2 * num - iter1->first - iter2->first) % num; v1 = b[iter1->second][0]; if (iter1->first == iter2->first) { v2 = b[iter1->second][1]; if (iter1->first == mainder) v3 = b[iter1->second][2]; else v3 = b[mainder][0]; if (v3 == -1 || v2 == -1) continue; } else { v2 = b[iter2->second][0]; if (iter1->first == mainder) v3 = b[iter1->second][1]; else if (iter2->first == mainder) v3 = b[iter2->second][1]; else v3 = b[mainder][0]; if (v3 == -1 || v2 == -1) continue; } ll tem = v1 + v2 + v3; if (ans < tem)ans = tem; } } printf("%lld", ans); return 0; }