103. 電影
莫斯科正在舉辦一個大型國際會議,有n個來自不同國家的科學家參會。
每個科學家都只懂得一種語言。
為了方便起見,我們把世界上的所有語言用1到109之間的整數編號。
在會議結束后,所有的科學家決定一起去看場電影放松一下。
他們去的電影院里一共有m部電影正在上映,每部電影的語音和字幕都采用不同的語言。
對于觀影的科學家來說,如果能聽懂電影的語音,他就會很開心;如果能看懂字幕,他就會比較開心;如果全都不懂,他就會不開心。
現在科學家們決定大家看同一場電影。
請你幫忙選擇一部電影,可以讓觀影很開心的人最多。
如果有多部電影滿足條件,則在這些電影中挑選觀影比較開心的人最多的那一部。
輸入格式
第一行輸入一個整數n,代表科學家的數量。
第二行輸入n個整數a1,a2…an,其中ai表示第i個科學家懂得的語言的編號。
第三行輸入一個整數m,代表電影的數量。
第四行輸入m個整數b1,b2…bm,其中bi表示第i部電影的語音采用的語言的編號。
第五行輸入m個整數c1,c2…cm,其中ci表示第i部電影的字幕采用的語言的編號。
請注意對于同一部電影來說,bi≠ci。
同一行內數字用空格隔開。
輸出格式
輸出一個整數,代表最終選擇的電影的編號。
如果答案不唯一,輸出任意一個均可。
數據范圍
1≤n,m≤200000,
1≤ai,bi,ci≤109
輸入樣例:
3
2 3 2
2
3 2
2 3
輸出樣例:
2
#include <iostream>
#include <algorithm>
#include <cstring>using namespace std;const int N = 200010;
int n, m, a[N], x[N], y[N], cinema[N*3], tot = 0, k, ans[N*3];int find(int f)
{return lower_bound(cinema + 1, cinema + k + 1, f) - cinema; // 返回找到的對應下標
}int main()
{cin >> n;for(int i = 1; i <= n; i++){cin >> a[i]; //n個整數a1,a2…an,其中ai表示第i個科學家懂得的語言的編號。cinema[++tot] = a[i];}cin >> m;for(int i = 1; i <= m; i++){cin >> x[i];cinema[++tot] = x[i];}for(int i = 1;i <= m; i++){cin >> y[i];cinema[++tot] = y[i];}//下面步驟為離散化sort(cinema + 1, cinema + tot + 1);k = unique(cinema + 1, cinema + tot + 1) - (cinema + 1);memset(ans, 0, sizeof(ans)); // 初始化ans 為0for(int i = 1; i <=n; i++) ans[find(a[i])]++; //第i個科學家懂得的語言的編號int ans0 = 1, ans1 = 0, ans2 = 0;for(int i = 1; i <=m; i++) //從1 到 m{int ansx = ans[find(x[i])], ansy = ans[find(y[i])];if(ansx > ans1 || (ansx == ans1 && ansy > ans2)){ans0 = i;ans1 = ansx;ans2 = ansy;}}cout << ans0 <<endl;// cout << ans1 <<endl;// cout << ans2 <<endl;return 0;
}
104. 貨倉選址
在一條數軸上有 N 家商店,它們的坐標分別為 A1~AN。
現在需要在數軸上建立一家貨倉,每天清晨,從貨倉到每家商店都要運送一車商品。
為了提高效率,求把貨倉建在何處,可以使得貨倉到每家商店的距離之和最小。
輸入格式
第一行輸入整數N。
第二行N個整數A1~AN。
輸出格式
輸出一個整數,表示距離之和的最小值。
數據范圍
1≤N≤100000
輸入樣例:
4
6 2 9 1
輸出樣例:
12
#include <iostream>
#include <algorithm>using namespace std;const int N = 100010;
int n, a[N];int main()
{cin >> n;for(int i = 1; i <= n; i++) cin >> a[i];sort(a + 1, a + n + 1); //排序int ans = 0;int zw = a[n/2 + 1];for(int i = 1; i <= n; i++)ans += abs(a[i] - zw);cout << ans <<endl;return 0;
}
105. 七夕祭
七夕節因牛郎織女的傳說而被扣上了「情人節」的帽子。
于是TYVJ今年舉辦了一次線下七夕祭。
Vani同學今年成功邀請到了cl同學陪他來共度七夕,于是他們決定去TYVJ七夕祭游玩。
TYVJ七夕祭和11區的夏祭的形式很像。
矩形的祭典會場由N排M列共計N×M個攤點組成。
雖然攤點種類繁多,不過cl只對其中的一部分攤點感興趣,比如章魚燒、蘋果糖、棉花糖、射的屋……什么的。
Vani預先聯系了七夕祭的負責人zhq,希望能夠通過恰當地布置會場,使得各行中cl感興趣的攤點數一樣多,并且各列中cl感興趣的攤點數也一樣多。
不過zhq告訴Vani,攤點已經隨意布置完畢了,如果想滿足cl的要求,唯一的調整方式就是交換兩個相鄰的攤點。
兩個攤點相鄰,當且僅當他們處在同一行或者同一列的相鄰位置上。
由于zhq率領的TYVJ開發小組成功地扭曲了空間,每一行或每一列的第一個位置和最后一個位置也算作相鄰。
現在Vani想知道他的兩個要求最多能滿足多少個。
在此前提下,至少需要交換多少次攤點。
輸入格式
第一行包含三個整數N和M和T,T表示cl對多少個攤點感興趣。
接下來T行,每行兩個整數x, y,表示cl對處在第x行第y列的攤點感興趣。
輸出格式
首先輸出一個字符串。
如果能滿足Vani的全部兩個要求,輸出both;
如果通過調整只能使得各行中cl感興趣的攤點數一樣多,輸出row;
如果只能使各列中cl感興趣的攤點數一樣多,輸出column;
如果均不能滿足,輸出impossible。
如果輸出的字符串不是impossible, 接下來輸出最小交換次數,與字符串之間用一個空格隔開。
數據范圍
1≤N,M≤100000,
0≤T≤min(N?M,100000),
1≤x≤N,
1≤y≤M
輸入樣例:
2 3 4
1 3
2 1
2 2
2 3
輸出樣例:
row 1
#include <iostream>
#include <algorithm>
#include <cstring>using namespace std;const int N = 100010;
int n, m, t, x[N], y[N], a[N], s[N];int main()
{cin >> n >> m >> t;for(int i = 1; i <= t; i++) cin >> x[i] >> y[i];bool row = !(t % n), col = !(t % m);if(row){if(col) cout << "both ";else cout << "row ";}else{if(col) cout << "column ";else {cout << "impossible" << endl;return 0;}}long long ans = 0;// 這里必須得long long,不然 溢出 T.Tif(row){int num = t / n;memset(a, 0, sizeof(a));for(int i = 1; i <= t; i++) a[x[i]]++;for(int i = 1; i <= n; i++) a[i] -= num; //每個人的紙牌都減去t / ns[0] = 0;//求前綴和for(int i = 1; i <= n; i++) s[i] = s[i - 1] + a[i]; //動態規劃的思想求前綴和sort(s + 1, s + n + 1);//"轉換為貨倉選址問題"for(int i = 1; i <=n; i++) ans += abs(s[i] - s[(n + 1) >> 1] ); //求中位數 s [(n+1) >> 1] 或者 s[n/2 + 1]}if(col){int num = t / m;memset(a, 0, sizeof(a));for(int i = 1; i <= t; i++) a[y[i]]++;for(int i = 1; i <= m; i++) a[i] -= num;s[0] = 0;for(int i = 1; i <= m; i++) s[i] = s[i - 1] + a[i];sort(s + 1, s + m + 1);for(int i = 1; i <= m; i++) ans += abs(s[i] - s[(m + 1) >> 1] );// for (int i = 1; i <= m / 2; i++) ans += s[m-i+1] - s[i];}cout << ans << endl;return 0;}
106. 動態中位數
依次讀入一個整數序列,每當已經讀入的整數個數為奇數時,輸出已讀入的整數構成的序列的中位數。
輸入格式
第一行輸入一個整數P,代表后面數據集的個數,接下來若干行輸入各個數據集。
每個數據集的第一行首先輸入一個代表數據集的編號的整數。
然后輸入一個整數M,代表數據集中包含數據的個數,M一定為奇數,數據之間用空格隔開。
數據集的剩余行由數據集的數據構成,每行包含10個數據,最后一行數據量可能少于10個,數據之間用空格隔開。
輸出格式
對于每個數據集,第一行輸出兩個整數,分別代表數據集的編號以及輸出中位數的個數(應為數據個數加一的二分之一),數據之間用空格隔開。
數據集的剩余行由輸出的中位數構成,每行包含10個數據,最后一行數據量可能少于10個,數據之間用空格隔開。
輸出中不應該存在空行。
數據范圍
1≤P≤1000,
1≤M≤9999
輸入樣例:
3
1 9
1 2 3 4 5 6 7 8 9
2 9
9 8 7 6 5 4 3 2 1
3 23
23 41 13 22 -3 24 -31 -11 -8 -7
3 5 103 211 -311 -45 -67 -73 -81 -99
-33 24 56
輸出樣例:
1 5
1 2 3 4 5
2 5
9 8 7 6 5
3 12
23 23 22 22 13 3 5 5 3 -3
-7 -3
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>using namespace std;const int N = 10010;int main()
{int t;cin >> t;while(t--){int x, m;cin >> x >> m;cout << x << " " << (m+1)/2 <<endl;priority_queue<int> max_heap; //大根堆priority_queue<int,vector<int>,greater<int>> min_heap; //小根堆int cnt = 0;for(int i = 1; i <= m; i++){int now;cin >> now;if(min_heap.empty())min_heap.push(now);else{if(now > min_heap.top()) min_heap.push(now);else max_heap.push(now);while(min_heap.size() < max_heap.size()){min_heap.push(max_heap.top());max_heap.pop();}while(min_heap.size() > max_heap.size() + 1){max_heap.push(min_heap.top());min_heap.pop();}}if(i & 1) //奇數輸出{++cnt;cout << min_heap.top() <<" ";if(cnt % 10 == 0) puts(""); // 輸出換行,每行包含10個數據}}puts(""); //輸入完數據換行}return 0;
}
107. 超快速排序
在這個問題中,您必須分析特定的排序算法----超快速排序。
該算法通過交換兩個相鄰的序列元素來處理n個不同整數的序列,直到序列按升序排序。
對于輸入序列9 1 0 5 4,超快速排序生成輸出0 1 4 5 9。
您的任務是確定超快速排序需要執行多少交換操作才能對給定的輸入序列進行排序。
輸入格式
輸入包括一些測試用例。
每個測試用例的第一行輸入整數n,代表該用例中輸入序列的長度。
接下來n行每行輸入一個整數ai,代表用例中輸入序列的具體數據,第i行的數據代表序列中第i個數。
當輸入用例中包含的輸入序列長度為0時,輸入終止,該序列無需處理。
輸出格式
對于每個需要處理的輸入序列,輸出一個整數op,代表對給定輸入序列進行排序所需的最小交換操作數,每個整數占一行。
數據范圍
0≤N<500000,
0≤ai≤999999999
輸入樣例:
5
9
1
0
5
4
3
1
2
3
0
輸出樣例:
6
0
#include <iostream>
#include <algorithm>
#include <cstring>#define ll long longusing namespace std;
const int N = 500010;
ll n, a[N], b[N];
ll ans;void merge(int l, int mid, int r)
{if(l == r) return; //只剩一個數,返回merge(l, l + mid >> 1, mid);merge(mid + 1, mid + 1 + r >> 1, r);int i = l, j = mid + 1; //分成左右兩邊for(int k = l; k <= r; k++){if(j > r || (i <= mid && a[i] <= a[j])) b[k] = a[i++]; //j > r 表示只剩左邊,或者,兩邊都有比較a[i]和a[j] 較小的入列else{b[k] = a[j++];ans += mid - i + 1;}}for(int k = l; k <= r; k++) a[k] = b[k]; // 把臨時存放數組b的放回a數組
}void q_sort()
{for(int i = 1; i <= n; i++) cin >> a[i];ans = 0;merge(1, (1 + n) >> 1, n);cout << ans << endl;
}int main()
{while(cin >> n && n) q_sort();return 0;
}
108. 奇數碼問題
你一定玩過八數碼游戲,它實際上是在一個3×3的網格中進行的,1個空格和1~8這8個數字恰好不重不漏地分布在這3×3的網格中。
例如:
5 2 8
1 3 _
4 6 7
在游戲過程中,可以把空格與其上、下、左、右四個方向之一的數字交換(如果存在)。
例如在上例中,空格可與左、上、下面的數字交換,分別變成:
5 2 8 5 2 5 2 8
1 3 1 3 8 1 3 7
4 6 7 4 6 7 4 6 _
奇數碼游戲是它的一個擴展,在一個n×n的網格中進行,其中n為奇數,1個空格和1~n2?1這n2?1個數恰好不重不漏地分布在n×n的網格中。
空格移動的規則與八數碼游戲相同,實際上,八數碼就是一個n=3的奇數碼游戲。
現在給定兩個奇數碼游戲的局面,請判斷是否存在一種移動空格的方式,使得其中一個局面可以變化到另一個局面。
輸入格式
多組數據,對于每組數據:
第1行輸入一個整數n,n為奇數。
接下來n行每行n個整數,表示第一個局面。
再接下來n行每行n個整數,表示第二個局面。
局面中每個整數都是0~n2?1之一,其中用0代表空格,其余數值與奇數碼游戲中的意義相同,保證這些整數的分布不重不漏。
輸出格式
對于每組數據,若兩個局面可達,輸出TAK,否則輸出NIE。
數據范圍
1≤n<500
輸入樣例:
3
1 2 3
0 4 6
7 5 8
1 2 3
4 5 6
7 8 0
1
0
0
輸出樣例:
TAK
TAK
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>using namespace std;int n;
long long ans;
vector <int> a[2];
const int N = 510 * 510 + 10;
int c[N];void merge(int k, int l, int mid, int r)
{int x = l, y = mid + 1; //分成兩部分 x左 y右for(int i = l; i <= r; i++){if(y > r || (x <= mid && a[k][x] < a[k][y]) ) c[i] = a[k][x++]; //或 后面的部分最好加括號else c[i] = a[k][y++], ans += mid - x + 1; //ans 是加一啊}for(int i = l; i <=r; i++) a[k][i] = c[i];
}void mergesort(int k, int l, int r)
{if(l == r) return;int mid = (l + r) / 2;mergesort(k, l, mid); //遞歸左半部分mergesort(k, mid + 1, r); //遞歸右半部分merge(k, l, mid, r); //合并
}long long calc(int k)
{ans = 0;mergesort(k, 0, n*n - 1);return ans;
}int main()
{while(cin >> n){a[0].clear();a[1].clear();for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++){int x; scanf("%d", &x); //要用這種輸入方式 才不會Segmentation Fault cin >> x 錯誤if (x) a[0].push_back(x); //除了0都push進數組里}for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++){int x; scanf("%d", &x); //要用這種輸入方式 才不會Segmentation Faultif(x) a[1].push_back(x);// while( (cin >> x) && x != 0) a[1].push_back(x); //錯誤}puts( a[0].size() && (calc(1) - calc(0) & 1) ? "NIE" : "TAK"); //判斷逆序對是不是偶數,偶數TAK,奇數NIE 奇偶性質 // if( (calc(0) & 1) == (calc(1) & 1) ) puts("TAK"); //第一個局面和第二個局面 逆序對個數相同,即奇偶性相同// else puts("NIE");}
}