---
tags: Coding
---
# APCS 2022 6/13
## P1 數字遊戲
https://zerojudge.tw/ShowProblem?problemid=i399
:::spoiler code
```cpp=
#include<bits/stdc++.h>
#define all(a) a.begin(),a.end()
using namespace std;
int main () {
vector<int> A(3);
for(int i=0;i<3;i++)cin>>A[i];
sort(all(A),[](int a,int b){return a>b;});
int a=1,b=1;
bool c=true;
for(int i=1;i<3;i++){
if(A[i]==A[i-1]&&c)a++;
else c=false;
if(A[i]==A[i-1]&&!c)b++;
if(max(a,b)==b){
a=b;
b=1;
c=true;
}
}
A.erase(unique(all(A)),A.end());
cout<<a<<" ";
for(auto i:A)cout<<i<<" ";
return 0;
}
```
:::
## P2 字串密碼
https://zerojudge.tw/ShowProblem?problemid=i400
### 字元陣列版
:::spoiler code
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main(){
cin.sync_with_stdio(0);
cin.tie(0);
int m,n;
while(cin>>m>>n){
char E[105][105],tran[300],str[105];
int cnt[105]={0};
string s;
for(int i=0;i<m;i++){
cin>>s;
for(int j=0;j<n;j++){
E[i][j]=s[j];
cnt[i]+=s[j]-48;//0的ascii是48
}
}
cin>>s;
for(int i=0;i<n;i++){
str[i]=s[i];
}
for(int i=m-1;i>=0;i--){
int f=150;
int b=151;
for(int j=n-1;j>=0;j--){
if(E[i][j]=='0'){
tran[f]=str[j];
f--;
}
if(E[i][j]=='1'){
tran[b]=str[j];
b++;
}
}
f++;
b--;
if(cnt[i]%2==1){
if(n%2){
for(int k=f;k<(n/2+f);k++){
swap(tran[k],tran[k+n/2+1]);
}
}
if(n%2==0){
for(int k=f;k<(n/2+f);k++){
swap(tran[k],tran[k+n/2]);
}
}
}
for(int k=f,i=0;k!=b+1;k++,i++){
str[i]=tran[k];
}
}
for(int i=0;i<n;i++) cout<<str[i];
}
return 0;
}
```
:::
### string版
:::spoiler code
```cpp=
#include <bits/stdc++.h>
using namespace std;
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int m,n;
vector<string> pasw;
while(cin>>m>>n){
string str,trans;
int cnt=0;
for(int i=0;i<m;i++){
string s;
cin>>s;
pasw.push_back(s);
}
cin>>str;
for(int i=m-1;i>=0;i--){
cnt=0;
trans="";
for(int k=n-1;k>=0;k--){
if(pasw[i][k]=='1'){
trans.append(str,k,1);
cnt++;
}
if(pasw[i][k]=='0'){
trans.insert(0,str,k,1);
}
}
if(cnt%2){
if(n%2){
trans=trans.substr(n/2+1,n/2)+trans.substr(n/2,1)+trans.substr(0,n/2);
}
if(!(n%2)){
trans=trans.substr(n/2,n/2)+trans.substr(0,n/2);
}
}
str=trans;
}
cout<<str;
}
}
```
:::
## P3 雷射測試
https://zerojudge.tw/ShowProblem?problemid=i401
### 想法一 failed(tle):
抓一隻螞蟻慢慢爬每爬一格,都用二分搜檢查是否與鏡子重疊。
但時間複雜度太久
:::spoiler code
```cpp=
#include<bits/stdc++.h>
#define N 20050
#define all(a) a.begin(),a.end()
using namespace std;
struct pos{
int x,y,t;
};
void debug(vector<pos>&a){
for(auto i:a){
cout<<i.x<<" "<<i.y<<" "<<i.t<<endl;
}
}
bool cmp(const pos &a,const pos &b){
if(a.x == b.x && a.y == b.y)return a.t<b.t;
else if(a.x == b.x)return a.y<b.y;
else return a.x<b.x;
}
int main () {
int m;
while(cin>>m){
vector<pos> P;
int X=0,Y=0;
int dx=1,dy=0;
int R=0,L=0,T=0,B=0;//right,left,top,bottom
int cnt=0;
for(int i=0;i<m;i++){
pos k;
cin>>k.x>>k.y>>k.t;
R=max(k.x,R);
T=max(k.y,T);
B=min(k.y,B);
P.push_back(k);
}//P是所有鏡子的座標
sort(all(P),cmp);
while(1){
X+=dx;
Y+=dy;
pos p1={X,Y,0};
pos p2={X,Y,1};
if(X<L || X>R || Y>T || T<B)break;
if(binary_search(all(P),p1,cmp)){// mirror / //
cnt++;
if(dx==1 && dy==0){
dx=0;
dy=1;
}else if(dx==0 && dy==1){
dx=1;
dy=0;
}else if(dx==-1 && dy==0){
dx=0;
dy=-1;
}else if(dx==0 && dy==-1){
dx=-1;
dy=0;
}
}else if(binary_search(all(P),p2,cmp)){// mirror \ //
cnt++;
if(dx==1 && dy==0){
dx=0;
dy=-1;
}else if(dx==0 && dy==1){
dx=-1;
dy=0;
}else if(dx==-1 && dy==0){
dx=0;
dy=1;
}else if(dx==0 && dy==-1){
dx=1;
dy=0;
}
}
}
cout<<cnt;
}
return 0;
}
```
:::
### 想法二(sucess):
https://www.youtube.com/watch?v=ZDoEDTR6ftI
參考吳邦一教授,幫每隔鏡子找鄰居。
**找南北鄰居方式**: 座標先依照x由小到大當遇到兩個x座標一樣,就看y座標,y小的在南邊,y大的在北邊,接著用二維陣列nb[N][4]代表每個鏡子四個方向鄰居座標,存對方的id(for讀進的順序)。找東西鄰居依此類推。
**模擬**: 一開始方向往東,然後遇到的第一個鏡子一定會在y=0。接下來用一個二維陣列mir[2][4]代表折射後轉向的方向。方向轉完後在看下一個方向有沒有鏡子,沒有則是-1。
:::spoiler code
```cpp=
#include<bits/stdc++.h>
#define N 250010
#define east 0
#define south 1
#define west 2
#define north 3
using namespace std;
typedef struct{
int x,y,id;
}pos;
bool cmpx(pos a,pos b){
if(a.x==b.x)return a.y<b.y;
return a.x<b.x;
}
bool cmpy(pos a,pos b){
if(a.y==b.y)return a.x<b.x;
return a.y<b.y;
}
int mir[2][4]={{north,west,south,east},{south,east,north,west}};/* mir 0=/ 1=\ */
pos tem[N];
int main () {
int m;
while(cin>>m){
int nb[N][4]={0};//neighbor
int me,cnt=0;
int t[N];
for(int i=0;i<N;i++)for(int j=0;j<4;j++)nb[i][j]=-1;
for(int i=0;i<m;i++){
cin>>tem[i].x>>tem[i].y>>t[i];
tem[i].id=i;
}
sort(tem,tem+m,cmpx);
for(int i=0;i<m-1;i++){
if(tem[i].x==tem[i+1].x){
nb[tem[i].id][north]=tem[i+1].id;
nb[tem[i+1].id][south]=tem[i].id;
}
}
sort(tem,tem+m,cmpy);
for(int i=0;i<m-1;i++){
if(tem[i].y==tem[i+1].y){
nb[tem[i].id][east]=tem[i+1].id;
nb[tem[i+1].id][west]=tem[i].id;
}
}
bool finded=0;
for(int i=0;i<m;i++){
if(tem[i].y==0){
int cur=tem[i].id;
int dir=east;
while(cur!=-1){
cnt++;
dir=mir[t[cur]][dir];
cur=nb[cur][dir];
}
cout<<cnt;
finded =1;
break;
}
}
if(!finded){
cout<<0;
}
}
return 0;
}
```
:::
## P4 內積
https://zerojudge.tw/ShowProblem?problemid=i402
### 想法一(tle):
暴力解直接跟它拚,把所有可能都跑過一遍。
:::spoiler code
```cpp=
#include<bits/stdc++.h>
#define all(a) a.begin(),a.end()
#define pb push_back
using namespace std;
int main () {
int m,n,ss,sum=INT_MIN,cnt=0;
cin>>m>>n;
vector<int> A(m),B(n);
ss=min(m,n);
for(int i=0;i<m;i++)cin>>A[i];
for(int i=0;i<n;i++)cin>>B[i];
for(int p=0;p<2;p++){
for(int i=1;i<=ss;i++){
for(int j=0;j<m+1-i;j++){
for(int k=0;k<n+1-i;k++){
for(int l=0;l<i;l++){
cnt+=A[j+l]*B[k+l];
}
sum=max(sum,cnt);
cnt=0;
}
}
}
reverse(all(B));
}
cout<<sum;
}
```
:::
### 想法二:
用dp,建立一個二維表格dp[i][j]=A[i]*B[j],然後跑遍所有的格子,跑的時候就看看dp[i-1][j-1]有沒有大於零,有的化就dp[i][j]+=dp[i-1][j-1]。記得表格最左跟最上面都要先填入才能計算。
:::spoiler code
```cpp=
#include<bits/stdc++.h>
#define all(a) a.begin(),a.end()
using namespace std;
int dp[1001][1001];
int main () {
int m=0,n=0,sum=INT_MIN;
cin>>m>>n;
vector<int> A(m),B(n);
for(int i=0;i<m;i++)cin>>A[i];
for(int i=0;i<n;i++)cin>>B[i];
for(int k=0;k<2;k++){
for(int j=0;j<n;j++){
dp[0][j]=A[0]*B[j];
sum=max(sum,dp[0][j]);
}
for(int i=1;i<m;i++){
dp[i][0]=A[i]*B[0];
sum=max(sum,dp[i][0]);
for(int j=1;j<n;j++){
dp[i][j]=A[i]*B[j];
if(dp[i-1][j-1]>0)dp[i][j]+=dp[i-1][j-1];
sum=max(sum,dp[i][j]);
}
}
reverse(all(B));
}
cout<<sum;
}
```
:::