# APCS 2022/6 題解 ## ==數字遊戲== ### <font color="0E81A6">題目</font> [數字遊戲](https://zerojudge.tw/ShowProblem?problemid=i399) ### <font color="0E81A6">核心</font> 陣列、排序 ### <font color="0E81A6">思路</font> 大到小排序,扣掉重複。 ```c++= #include<bits/stdc++.h> using namespace std; int main() { int A[3]; scanf("%d%d%d",A,A+1,A+2); int num=1; sort(A,A+3,greater<int>()); for(int i=1;i<3;i++) { if(A[i]==A[i-1]) num++; } printf("%d %d ",num,A[0]); for(int i=1;i<3;i++) { if(A[i]!=A[i-1]) printf("%d ",A[i]); } } ``` ## ==字串解碼== ### <font color="0E81A6">題目</font> [字串解碼](https://zerojudge.tw/ShowProblem?problemid=i400) ### <font color="0E81A6">核心</font> 二維陣列、模擬、String ### <font color="0E81A6">思路</font> 注意字串長度奇數和偶數要分別判斷。 ```c++= #include<bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); int m,n; cin>>m>>n; string s; int code[105][105],oddNum[105]; for(int i=0;i<m;i++) { cin>>s; for(int j=0;j<n;j++) { code[i][j]=s[j]-'0'; if(code[i][j]&1) oddNum[i]++; } } string str1; cin>>str1; for(int i=m-1;i>=0;i--) { string str2,temp1,temp2; for(int j=n-1;j>=0;j--) { if(code[i][j]&1) str2=str2+str1[j]; else str2=str1[j]+str2; } if(oddNum[i]&1 && n&1) { temp1=str2.substr(0,n/2); temp2=str2.substr(n/2+1); str2=temp2+str2[n/2]+temp1; } else if(oddNum[i]&1) { temp1=str2.substr(0,n/2); temp2=str2.substr(n/2); str2=temp2+temp1; } str1=str2; } cout<<str1<<endl; } ``` ## ==雷射測試== ### <font color="0E81A6">題目</font> [雷射測試](https://zerojudge.tw/ShowProblem?problemid=i401) ### <font color="0E81A6">核心</font> 二分搜、模擬 ### <font color="0E81A6">思路</font> 當入射方向為向左或向右時,X值固定,要考慮此時最接近Y值。 當入射方向為向上或向下時,Y值固定,要考慮此時最接近X值。 由於最接近的值有可能是大於或小於,故分別用upper_bound和lower_bound。 若找不到值則break。 ```c++= #include<bits/stdc++.h> using namespace std; #define N 250005 #define M 30005 #define piib pair<pair<int,int>,bool> #define ff first.first #define fs first.second set<piib> Xst; //(y,x),grs set<piib> Yst; //(x,y),grs //0 up, 1 down, 2 left, 3 right int main() { int n; scanf("%d",&n); int x,y,g; for(int i=1;i<=n;i++) { scanf("%d%d%d",&x,&y,&g); Xst.insert({{y,x},g}); Yst.insert({{x,y},g}); } piib now={{0,0},0}; //x,y,g int dir=3; int ans=0; while(true) { if(dir==0) { auto it=Yst.upper_bound(now); if(it==Yst.end()) break; piib next=*it; if(next.ff!=now.ff) break; ans++; bool grass=next.second; if(grass) dir=2; else dir=3; now=next; } else if(dir==1) { auto it=Yst.lower_bound(now); if(it==Yst.begin()) break; piib next=*(prev(it)); if(next.ff!=now.ff) break; ans++; bool grass=next.second; if(grass) dir=3; else dir=2; now=next; } else if(dir==2) { auto it=Xst.lower_bound({{now.fs,now.ff},now.second}); if(it==Xst.begin()) break; piib next=*(prev(it)); if(next.ff!=now.fs) break; ans++; bool grass=next.second; if(grass) dir=0; else dir=1; now={{next.fs,next.ff},next.second}; } else { auto it=Xst.upper_bound({{now.fs,now.ff},now.second}); if(it==Xst.end()) break; piib next=*it; if(next.ff!=now.fs) break; ans++; bool grass=next.second; if(grass) dir=1; else dir=0; now={{next.fs,next.ff},next.second}; } } printf("%d\n",ans); } ``` ## ==內積== ### <font color="0E81A6">題目</font> [內積](https://zerojudge.tw/ShowProblem?problemid=i402) ### <font color="0E81A6">核心</font> dp、LCS、枚舉 ### <font color="0E81A6">思路</font> 前i對前j。 dp記錄此時最大內積值,presum記錄先前連續的內積值。 注意邊界(這裡是單一個內積的時候)。 注意需要將一個陣列反過來做一次。 ```c++= #include<bits/stdc++.h> using namespace std; #define N 1005 int n,m,ans=INT_MIN; int A[N],B[N],dp[N][N],presum[N][N]; void caculate() { memset(dp,0,sizeof(dp)); memset(presum,0,sizeof(presum)); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { dp[i][j]=A[i]*B[j]; if(i>1&&j>1) { dp[i][j]=max({A[i]*B[j],dp[i-1][j-1],presum[i-1][j-1]+A[i]*B[j]}); } presum[i][j]=max(A[i]*B[j],presum[i-1][j-1]+A[i]*B[j]); ans=max(ans,dp[i][j]); } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",A+i); for(int i=1;i<=m;i++) scanf("%d",B+i); caculate(); for(int i=1;i<=n/2;i++) swap(A[i],A[n+1-i]); caculate(); printf("%d\n",ans); } ```