# APCS 2021/09 題解
## ==七言對聯==
### <font color="0E81A6">題目</font>
[七言對聯](https://zerojudge.tw/ShowProblem?problemid=g275)
### <font color="0E81A6">核心</font>
條件判斷
### <font color="0E81A6">思路</font>
```c++=
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
int first[7],second[7];
while(n--)
{
bool mistake=false;
for(int i=0;i<7;i++) scanf("%d",first+i);
for(int i=0;i<7;i++) scanf("%d",second+i);
if(first[1]==first[3]||first[1]!=first[5]||second[1]==second[3]||second[1]!=second[5])
{
printf("A"),mistake=true;
}
if(first[6]==0||second[6]==1) printf("B"),mistake=true;
if(first[1]==second[1]||first[3]==second[3]||first[5]==second[5]) printf("C"),mistake=true;
if(!mistake) printf("None");
printf("\n");
}
}
```
## ==魔王迷宮==
### <font color="0E81A6">題目</font>
[魔王迷宮](https://zerojudge.tw/ShowProblem?problemid=g276)
### <font color="0E81A6">核心</font>
模擬
### <font color="0E81A6">思路</font>
注意是同時移動、同時放炸彈。
```c++=
#include<bits/stdc++.h>
using namespace std;
int place[105][105]={0};
struct boss
{
int r,c,s,t;
};
int main()
{
int n,m,k;
vector<boss> kings;
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<k;i++)
{
int r,c,s,t;
scanf("%d%d%d%d",&r,&c,&s,&t);
kings.push_back({r,c,s,t});
}
int ans=0;
set<pair<int,int>> S;
while(!kings.empty())
{
int x,y;
vector<int> to_remove;
for(int i=0;i<kings.size();i++)
{
x=kings[i].r,y=kings[i].c;
if(place[x][y]==0) ans++;
place[x][y]+=1;
}
for(int i=0;i<kings.size();i++)
{
x=kings[i].r+kings[i].s,y=kings[i].c+kings[i].t;
if(x<0||y<0||x>=n||y>=m||place[x][y]>=1) to_remove.push_back(i);
else kings[i].r=x,kings[i].c=y;
if(x>=0&&y>=0&&x<n&&y<m&&place[x][y]>=1) S.insert({x,y});
}
for (int i=to_remove.size()-1;i>=0;i--) kings.erase(kings.begin()+to_remove[i]);
while(!S.empty())
{
pair<int,int> p=*S.begin();
S.erase(p);
place[p.first][p.second]=0;
ans--;
}
}
printf("%d\n",ans);
}
```
## ==幸運數字==
### <font color="0E81A6">題目</font>
[幸運數字](https://zerojudge.tw/ShowProblem?problemid=g277)
### <font color="0E81A6">核心</font>
分治、線段樹
### <font color="0E81A6">90%解法(killed)思路</font>
只用分治的話會超時,但很簡單。
```c++=
#include<bits/stdc++.h>
using namespace std;
#define N 300005
#define pii pair<int,int> //ans sum
#define int long long
int n;
int number[N];
pii findn(int l,int r)
{
if(l+1==r) return {number[l],number[l]};
int lsum=0,rsum=0,ans;
int index=min_element(number+l,number+r)-number;
pii left,right;
if (index>l)
{
left=findn(l,index);
lsum=left.second;
}
if (index<r-1)
{
right=findn(index+1,r);
rsum=right.second;
}
if(lsum>rsum) ans=left.first;
else ans=right.first;
return {ans,lsum+rsum+number[index]};
}
signed main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",number+i);
pii ans=findn(0,n);
printf("%d\n",ans.first);
}
```
### <font color="0E81A6">AC解法思路</font>
需要使用線段樹來快速查詢區間最小值。
min_element函數複雜度是O(n)。
線段樹構樹複雜度也是O(n),但查詢和修改是O(logn),因此多次查詢的話,用線段樹會好很多。
```c++=
#include<bits/stdc++.h>
using namespace std;
#define N 300005
#define pii pair<int,int>
#define int long long
int n,number[N],psum[N]={0};
pii tree[4*N];
void build(int s,int t,int pos)
{
if(s==t)
{
tree[pos]={number[s],s};
return;
}
int m=(s+t)>>1;
build(s,m,2*pos+1),build(m+1,t,2*pos+2);
if(tree[2*pos+1].first<tree[2*pos+2].first) tree[pos]=tree[2*pos+1];
else tree[pos]=tree[2*pos+2];
return;
}
pii query(int l,int r,int s,int t,int pos)
{
if (r<s||t<l) return {LLONG_MAX, -1};
if(l<=s&&t<=r) return tree[pos];
int m=(s+t)>>1;
auto left=query(l,r,s,m,2*pos+1),right=query(l,r,m+1,t,2*pos+2);
if(left.first<right.first) return left;
else return right;
}
signed main()
{
scanf("%lld",&n);
for(int i=0;i<n;i++)
{
scanf("%lld",number+i);
psum[i]=number[i];
if(i!=0) psum[i]+=psum[i-1];
}
build(0,n-1,0);
int l=0,r=n-1;
while(l<r)
{
int m=query(l,r,0,n-1,0).second;
if(m==l) l=m+1;
else if(m==r) r=m-1;
else
{
if(psum[m-1]-psum[l]+number[l]>psum[r]-psum[m+1]+number[m+1]) r=m-1;
else l=m+1;
}
}
printf("%lld\n",number[l]);
}
```
## ==美食博覽會==
### <font color="0E81A6">題目</font>
[美食博覽會](https://zerojudge.tw/ShowProblem?problemid=g278)
### <font color="0E81A6">核心</font>
dp
### <font color="0E81A6">思路</font>
dp[i][j]表i個人從攤位0~j能吃多少個。
len[i]表第i個攤位開始最大不重複子序列。
```c++=
#include<bits/stdc++.h>
using namespace std;
#define N 1000005
int n,k,dp[22][N]={0};
int stall[N],visit[N]={false},len[N];
int ans=0;
int main()
{
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++) scanf("%d",stall+i);
queue<int> Q;
for(int i=n-1;i>=0;i--)
{
while(!Q.empty()&&visit[stall[i]])
{
visit[Q.front()]=false;
Q.pop();
}
Q.push(stall[i]);
visit[stall[i]]=true;
len[i]=Q.size();
dp[1][i+len[i]-1]=max(dp[1][i+len[i]-1], len[i]);
}
for(int i=1;i<=k;i++)
{
dp[i][i-1]=i;
for(int j=i;j<n;j++)
{
dp[i][j]=max(dp[i][j], dp[i][j-1]);
dp[i+1][j+len[j]-1] = max(dp[i+1][j+len[j]-1], dp[i][j-1]+len[j]);
}
}
printf("%d\n",dp[k][n-1]);
}
```