# **APCS實作題解** powered by hamster
* 第1題
算是APCS中簡單的第一題
以變數l跟r分別記錄 左邊食物數量 和 右邊食物數量
for迴圈跑一次e陣列 if(e[i]<x)成立就是左邊l++ 反之在右邊r++
l跟r比較
對大的進行輸出
而最後的位置一定是最右 或 最左
我當初懶惰直接用sort (也可找最大值 和 最小值?
一般sort後 e[0]是最左 e[n-1]是最右
O(nlogn)
```cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
int x,n;
cin>>x>>n;
vector<int> e(n,0);
for(int i=0;i<n;i++)
cin>>e[i];
sort(e.begin(),e.end());
int r=0,l=0;
for(int i=0;i<n;i++){
if(e[i]<x)
l++;
else
r++;
}
if(r>l)
cout<<r<<" "<<e[n-1]<<endl;
else
cout<<l<<" "<<e[0]<<endl;
return 0;
}
```
---
* 第2題
嗯這題有點難解釋
但直接暴力做是沒問題的
最重要的是 甚麼時候停止?
題目有說 其中數字只有0~1000 且每個數字獨特
如果有最差的情況就是每跑一次只解開一個配對
最多就要跑1000多次
所以跑1000多次後就是一定結束了 保險跑1005次owob
(應該可開bool 紀錄每回合有沒有數字被解開
但不能觀查ans值有沒有變化因為會忽略 數字0 被解開的狀況
O(nm*10^3)
```cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
vector<vector<int>> v(n,vector<int>(m,0));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
cin>>v[i][j];
}
int ans=0;
for(int l=0;l<1005;l++){
for(int i=0;i<n;i++){
int left=-2,leftj=-2;//紀錄左邊元素
for(int j=0;j<m;j++){
if(left==v[i][j]){
ans+=left;
v[i][j]=-1;
v[i][leftj]=-1;
}
if(v[i][j]==-1)continue;
leftj=j;
left=v[i][j];
}
}
for(int j=0;j<m;j++){
int up=-2,upi=-2;//紀錄上面元素
for(int i=0;i<n;i++){
if(up==v[i][j]){
ans+=up;
v[i][j]=-1;
v[upi][j]=-1;
}
if(v[i][j]==-1)continue;
upi=i;
up=v[i][j];
}
}
}
cout<<ans<<endl;
return 0;
}
```
---
* 第3題
這題有點複雜
直接BFS 就行 DFS容易堆疊溢位
bfs加入點時要先確定兩個有連通
if條件寫好穩穩過
function 當函式看就好不要太糾結(X
O(nm)
```cpp
#include<bits/stdc++.h>
using namespace std;
int dx[4]={-1,0,1,0},dy[4]={0,-1,0,1};
struct point{
int x,y;
point(int x,int y):x(x),y(y){
}
};
bool check_next(char c,int d){//確定該位置能接受哪些方向
if(c=='X')return 1;
if(c=='F'&&(d==0||d==1))return 1;
if(c=='H'&&(d==1||d==3))return 1;
if(c=='7'&&(d==0||d==3))return 1;
if(c=='I'&&(d==0||d==2))return 1;
if(c=='L'&&(d==1||d==2))return 1;
if(c=='J'&&(d==3||d==2))return 1;
return 0;
}
bool check_d(char c,int d){//確定所在方向能通往哪裡
if(c=='X')return 1;
if(c=='F'&&(d==3||d==2))return 1;
if(c=='H'&&(d==1||d==3))return 1;
if(c=='7'&&(d==1||d==2))return 1;
if(c=='I'&&(d==0||d==2))return 1;
if(c=='L'&&(d==0||d==3))return 1;
if(c=='J'&&(d==0||d==1))return 1;
return 0;
}
int main(){
int n,m;
cin>>n>>m;
vector<vector<char>> v(n+2,vector<char>(m+2,'0'));
vector<vector<int>> vis(n+2,vector<int>(m+2,0));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>v[i][j];
}
}
function<int(int,int)> bfs=[&](int x,int y){
int sum=1;
point s(x,y);
queue<point> q;
q.push(s);
while(!q.empty()){
point p=q.front();
q.pop();
for(int i=0;i<4;i++){
if(!check_d(v[p.x][p.y],i))continue;
int nx=p.x+dx[i],ny=p.y+dy[i];
if(!check_next(v[nx][ny],i))continue;
if(vis[nx][ny])continue;
vis[nx][ny]=1;
sum++;
q.push(point(nx,ny));
}
}
return sum;
};
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!vis[i][j]&&v[i][j]!='0'){
vis[i][j]=1;
ans=max(ans,bfs(i,j));
}
}
}
cout<<ans<<endl;
return 0;
}
```
---
* 第4題
如果k=0 很簡單->dp最大子數列
轉移式是 dp[i]=max(dp[i-1],0)+e[i];
但如果k!=0那就不是了
我們需要幫dp增維進行考慮 -> dp[i][j] 增加j代表用了多少金幣
可得到新的轉移式
`dp[i][j]=max(dp[i][j-1],dp[i-1][j]+e[i],dp[i][j-1])`
dp[i][j-1]好像不用 我考APCS太擔心加的
O(nk)
```cpp
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
int n,k;
cin>>n>>k;
vector<int> e(n);
vector<vector<int>> dp(n,vector<int>(k+1,0));
for(int i=0;i<n;i++)
cin>>e[i];
int ans=0;
dp[0][0]=e[0];
ans=max(e[0],ans);
for(int i=1;i<n;i++){
dp[i][0]=max(0LL,dp[i-1][0])+e[i];
ans=max(dp[i][0],ans);
for(int j=1;j<=k;j++){
dp[i][j]=max({dp[i-1][j]+e[i],dp[i-1][j-1],dp[i][j-1]});
ans=max(ans,dp[i][j]);
}
}
cout<<ans<<endl;
}
```
**心得**
歷次
![](https://hackmd.io/_uploads/Bk-d4_7z6.png)
![](https://hackmd.io/_uploads/Sy0uNd7G6.png)
祈禱自己實作能有5
owob