# APCS 2021/1 題解 ## ==購買力== ### <font color="0E81A6">題目</font> [購買力](https://zerojudge.tw/ShowProblem?problemid=f605) ### <font color="0E81A6">核心</font> 條件判斷 ### <font color="0E81A6">思路</font> 歷屆中算簡單的一題。 ```c++= #include<bits/stdc++.h> using namespace std; int main() { int n,d,num=0,sum=0; int A[3]; scanf("%d%d",&n,&d); for(int i=0;i<n;i++) { scanf("%d%d%d",A,A+1,A+2); if(abs(A[0]-A[1])>=d||abs(A[0]-A[2])>=d||abs(A[1]-A[2])>=d) num++,sum+=(A[0]+A[1]+A[2])/3; } printf("%d %d\n",num,sum); } ``` ## ==流量== ### <font color="0E81A6">題目</font> [流量](https://zerojudge.tw/ShowProblem?problemid=f606) ### <font color="0E81A6">核心</font> 二維陣列、模擬 ### <font color="0E81A6">思路</font> 沒想像中複雜,用兩個二維就能簡單模擬。 server[i][j]表編號i伺服器流向編號j城市的流量。 flow[i][[j]表編號i城市流向編號j城市的總流量。 ```c++= #include<bits/stdc++.h> using namespace std; int main() { int n,m,k; int server[55][55]; scanf("%d%d%d",&n,&m,&k); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) scanf("%d",&server[i][j]); } int minCost=INT_MAX; while(k--) { int flow[55][55]={0},city,cost=0; for(int i=0;i<n;i++) { scanf("%d",&city); for(int j=0;j<m;j++) { flow[city][j]+=server[i][j]; } } for(int i=0;i<m;i++) { for(int j=0;j<m;j++) { if(i==j) cost+=flow[i][j]; else { if(flow[i][j]>=1000) cost+=3000+2*(flow[i][j]-1000); else cost+=3*(flow[i][j]); } } } minCost=min(minCost,cost); } printf("%d\n",minCost); } ``` ## ==切割費用== ### <font color="0E81A6">題目</font> [切割費用](https://zerojudge.tw/ShowProblem?problemid=f607) ### <font color="0E81A6">核心</font> 排序、二分搜 ### <font color="0E81A6">思路</font> 切過後視為一端點,插入set,每次切割找尋最近左右端點。 ```c++= #include<bits/stdc++.h> using namespace std; #define LL long long #define pii pair<int,int> #define N 200005 int n,L; pii cut[N]; set<int> point; int main() { scanf("%d%d",&n,&L); for(int i=0;i<n;i++) { int locate,which; scanf("%d%d",&locate,&which); cut[i].first=which,cut[i].second=locate; } point.insert(0),point.insert(L); sort(cut,cut+n); LL cost=0; for(int i=0;i<n;i++) { int place=cut[i].second; auto it=point.lower_bound(place); int leftPoint=*(prev(it)),rightPoint=*it; cost+=rightPoint-leftPoint; point.insert(place); } printf("%lld\n",cost); } ``` ## ==飛黃騰達== ### <font color="0E81A6">題目</font> [飛黃騰達](https://zerojudge.tw/ShowProblem?problemid=f608) ### <font color="0E81A6">核心</font> 排序、二分搜 ### <font color="0E81A6">思路</font> 以x方向或y方向作排序,接著依序去找另一方向的最長遞增序列。 注意!tmp內所放的值非路徑解,tmp只能求最多經過點數量。 當tmp.back()小於目前所看的點另一方向值時,所進行的是tmp內值的修改(此時當前最佳路徑已不在tmp內,但最佳長度保持),若修改有助於後續推入更多點(tmp.back()也被修改為較小值),最佳路徑改變,長度增加,若修改無助於後續推入更多點,也不影響最佳長度。(當作是一種未知的考量) ```c++= #include<bits/stdc++.h> #define F first #define S second using namespace std; int n; vector<pair<int,int>>v; int main() { cin>>n; v.assign(n,{}); for(int i=0;i<n;i++)cin>>v[i].F>>v[i].S; sort(v.begin(),v.end()); vector<int>tmp; for(auto i:v) { if(tmp.empty()||tmp.back()<=i.S)tmp.push_back(i.S); else tmp[upper_bound(tmp.begin(),tmp.end(),i.S)-tmp.begin()]=i.S; } cout<<tmp.size(); } ```