# 上課例題

# b966: 第 3 題 線段覆蓋長度

給定一維座標上一些線段,求這些線段所覆蓋的長度,注意,重疊的部分只能算一次。

將每一條線段的起始點做排序,將起始位置設為第一條線段的頭,將結尾位置設為第一條線段的尾,再開始往後依序判別,

  1. 若現在的結尾位置已經超越了下一線段的頭,則將結尾位置定在下一個線段的尾
  2. 若現在的結尾位置未與下一線段的頭重疊,則使 cnt 加上目前累積的長度 (結尾位置 - 起始位置)
#include <bits/stdc++.h>
using namespace std;
typedef struct _node {
	int s;    // 頭
	int e;    // 尾
}Node;
bool cmp(Node p, Node q) {
	if (p.s == q.s) return (q.e> p.e);
	else return(p.s < q.s);
}
Node d[10000];
int main() {
	int n, cnt,start,end;
	while (cin>>n) {
		cnt = 0;
		for (int i = 0; i<n; i++) {
			cin>>d[i].s>>d[i].e;
		}
		sort(d, d + n, cmp); 
		for (int i = 0; i < n;i++) {
			start = d[i].s;
			end = d[i].e;
			while ((i + 1 < n) && d[i + 1].s < end) { 
				if (d[i + 1].e <= end) i++;
				else {
					end = d[i + 1].e; 
					i++;
				}
			}
			cnt += end - start; 
		}
        cout<<cnt<<endl;
	}
}

# 延伸練習

# g277: 3. 幸運數字

內容
在 n 個人之中,每個人被分配到一個號碼,記錄為 a1,a2,…,an,這些號碼彼此都不相同,我們要找出當中最幸運的一個
已知在 [L,R] 區間之中,最幸運號碼定義為:

  1. 當 L=R 時,幸運號碼為 a [L]
  2. 當 L<R 時,找出當中最小號碼的位置 m,並將整個區間區分為左邊 [L,m-1] 與右邊 [m+1,R],計算兩個區間各自的總和,總和比較大的區間即為幸運號碼所在的區間;如果兩個區間的總和相等,則幸運號碼位在右邊的區間,若區間不包含任何數字,總和視為 0

重複以上步驟直到收斂至 1. 時即可找到幸運號碼

尋找序列的最小值,可以透過先行將序列由小到大排序 (位置需另外紀錄),
如果該序列的最小值落在區間內,即可作為中心點。
判斷左、右邊大小可以透過實作前綴和的方式計算區間的加總。

#include <bits/stdc++.h>
#define int long long
#define N 300005
#define pii pair<int,int>
#define x first
#define y second
using namespace std;
int n,arr[N],pref[N];
pii sorted[N];
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>sorted[i-1].x;
        arr[i] = sorted[i-1].x;
        sorted[i-1].y = i;
        pref[i] = pref[i-1]+arr[i];
    }
    sort(sorted,sorted+n);
    int ind = 0,l = 1,r = n;
    while(r>l){
        while(sorted[ind].y > r || sorted[ind].y < l) ind++;
        int left = pref[sorted[ind].y-1] - pref[l-1];
        int right = pref[r] - pref[sorted[ind].y];
        if(left > right)
            r = sorted[ind].y-1;
        else
            l = sorted[ind].y+1;
    }
    cout<<arr[l]<<endl;
}

# a737: 10041 - Vito’s family

Vito 時常要拜訪所有的親戚,他希望從他的家到所有的親戚的家的距離的和為最小。
輸出從他的新家到所有的親戚的家的距離的和為最小為多少。

多個絕對值相加,最小值出現在排好數列的中位數時,用中位數帶入即可

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,t;
    cin>>n;
    while(n--){
        cin>>t;
        int a[t];
        for(int i = 0;i<t;i++){
            cin>>a[i];
        }
        sort(a,a+t);
        int sum = 0;
        int mid = a[t/2]; // 家的位置
        for(int i = 0;i<t;i++){
            sum  += abs(mid - a[i]);
        }
        cout<<sum<<endl;
    }
}

# d150: 11369 - Shopaholic

林希是個購物狂。每次只要有買二送一的折扣 (送掉其中價錢最低的),
她要買下店裡所有的商品。他想要減少她的支出。
你的工作便是找出林希最多可以省多少錢。

每一次結帳時,都取最貴的三個商品結帳,就可以讓送掉的金額最大。

#include <bits/stdc++.h>
using namespace std;
int main(){
    int n;
    while(cin>>n){
        for(int i=0;i<n;i++){
            int m,sum=0;
            cin>>m;
            int p[m];
            for(int j=0;j<m;j++)
                cin>>p[j];
            
            sort(p,p+m);
            
            for(int j=1;m-3*j>=0;j++)
                sum+=p[m-3*j];
            cout<<sum<<endl;
        }
    }
    return 0;
}

# d385: 10905 - Children's Game

你將會得到 N 個正整數,你可以將一個整數接在另一個整數之後以製造一個更大的整數。

排序完成後,全部字串照順序接起來即是答案。
例如給定的字串 "123"、“124”、“56”、90”,
按順序連接它們可得到 "1231245690"。
如果交換 "123"、“124”,可得到更好的結果 "1241235690"。

#include <bits/stdc++.h>
using namespace std;
bool cmp(string a,string b){
    return (a+b)>(b+a);
}
int main(){
    int n;
    string s[50];
    while(cin>>n&&n){
        for(int i=0;i<n;i++)
            cin>>s[i];
        sort(s,s+n,cmp);
        for(int i=0;i<n;i++)
            cout<<s[i];
        cout<<endl;
    }
}
更新於 閱讀次數

用實際行動犒賞爆肝的我😀

Zrn Ye LinePay

LinePay