---
title: 'AtCoder Beginner Contest 271'
disqus: hackmd
---
AtCoder Beginner Contest 271
===
[TOC]
### [A - 484558](https://atcoder.jp/contests/abc271/tasks/abc271_a) [ascii code]
:::info
小知識:當數字>10,可以下列關係式轉換成英文
(char)('A'+b-10)
:::
```csharp=
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin>>n;
int a=n/16,b=n%16;
if(a<=9)cout<<a;
else cout<<(char)('A'+a-10);
if(b<=9)cout<<b;
else cout<<(char)('A'+b-10);
return 0;
}
```
### [B - Maintain Multiple Sequences](https://atcoder.jp/contests/abc271/tasks/abc271_b) [vector]
:::info
看到大小不固定的陣列,當然是直接開vector動態改變他阿!
:::
```csharp=
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
vector<ll> vec[200010];
int main() {
ll n,q;
cin>>n>>q;
for(ll i=0;i<n;i++){
ll le;
cin>>le;
for(ll j=0,num;j<le;j++){
cin>>num;
vec[i].pb(num);
}
}
while(q--){
ll f,s;
cin>>f>>s;
cout<<vec[f-1][s-1]<<endl;
}
return 0;
}
```
### [C - Manga](https://atcoder.jp/contests/abc271/tasks/abc271_c) [雙指針]
:::danger
vec.erase()複雜度是O(n)!!!!!,所以會TLE。
:::
:::info
利用L、R維護左界(沒有第幾本書)、右界(目前有的書籍的最大編號),複雜度O(n)(當兩指針疊在一起時)
:::
```csharp=
#include <iostream>
#include <vector>
#define ll long long
using namespace std;
int main() {
ll sold=0,n;
cin>>n;
vector<ll> a(n);//紀錄有什麼書籍
vector<bool> vol(n+2,false);
for(ll i=0;i<n;i++){
cin>>a[i];
if(a[i]>n) sold++;//最多讀到第n本,第n+1本以後的賣出
else if(!vol[a[i]]) vol[a[i]]=1;//紀錄有的書
else sold++;//多於一本賣掉
}
ll l=1,r=n+1;//維護目前沒有的書、最大擁有編號多少的書
while(1){
while(vol[l]) l++;//連續讀下去
while(r!=0 && vol[r]==0) r--;//沒有這些書
if(sold>=2){//書不夠讀了,交換書
sold-=2;//少兩本
vol[l]=1;//換一本
}
else{
if(l>=r) break;//沒有的書編號>擁有的書編號,矛盾,停止
vol[r]=false;//賣掉一本
sold++;//多一本可能可以交換的書
}
}
cout<<l-1<<endl;//只能讀到l-1本
return 0;
}
```
TLE扣
```csharp=
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
vector<ll> sta;
int main() {
ios::sync_with_stdio(0);
cin.tie();cout.tie();
ll n;
cin>>n;
for(ll i=0,num;i<n;i++){
cin>>num;
sta.pb(num);
}
ll ans=0;
if((ll)sta.size()==1 && sta[0]==1){
cout<<1<<endl;
return 0;
}
else if((ll)sta.size()==1 && sta[0]!=1){
cout<<0<<endl;
return 0;
}
ll cnt=1;
sort(sta.begin(),sta.end());
while((ll)sta.size()>1){
if(sta[0]==cnt){
sta.erase(sta.begin());
ans+=1;
}
else{
sta.pop_back();
sta.pop_back();
ans++;
}
cnt++;
}
if(sta[0]==cnt) ans++;
cout<<ans<<endl;
return 0;
}
```
### [D - Flip and Adjust](https://atcoder.jp/contests/abc271/tasks/abc271_d) [dp]
:::info
通靈dp:
1. 定義初始狀態:
dp[0][0]=1,dp[0][x]=0(x>0)
2. 定義轉移式:
如果由第1張卡牌至第i張卡牌可以湊出j,定義dp[i][j]=1
3. dp性質:
如果$j+a_i \le S$,那dp[i+1][j+$a_i$]=1
如果$j+b_i \le S$,那dp[i+1][j+$b_i$]=1
4. 實作方法:
先掃過i,然後看($a_i+$多少$\le S$)有辦法走到,那就走那一格
:::
```csharp=
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll dp[110][10000];
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
ll n,s;
cin>>n>>s;
ll a[n],b[n];
for(ll i=0;i<n;i++) cin>>a[i]>>b[i];
dp[0][0]=1;
for(ll i=0;i<n;i++){
for(ll j=0;j<=s;j++){
if(dp[i][j]){
if(j+a[i]<=s){
dp[i+1][j+a[i]]=1;
}
if(j+b[i]<=s){
dp[i+1][j+b[i]]=1;
}
}
}
}
if(dp[n][s]){
cout<<"Yes\n";
string str(n,'H');
for(ll i=n-1;i>=0;i--){
if(s>=a[i] && dp[i][s-a[i]]){//可以從前一格跳來
str[i]='H';
s-=a[i];
}
else{
str[i]='T';
s-=b[i];
}
}
cout<<str<<endl;
}
else cout<<"No\n";
return 0;
}
```
### [E - Subsequence Path ](https://atcoder.jp/contests/abc271/tasks/abc271_e)[dp]
:::info
看到這題超級通靈,竟然把圖論題當成dp來做。
定義dist[i]代表到i點距離的最小值,dist[0]=0(起點),
走不到設成無限大。
:::
:::success
注意到因為是有向圖,所以b[e]必由a[e]走邊權c[e]的邊而來,
故dist[b[e]]=max(dist[b[e]],a[e]+c[e])
:::
```csharp=
#include <iostream>
#include <vector>
#define ll long long
#define inf 10000000000000000
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
ll n,m,k;
cin>>n>>m>>k;
vector<ll> a(m),b(m),c(m),dist(n,inf);
for(ll i=0;i<m;i++) {
cin>>a[i]>>b[i]>>c[i];
a[i]--;b[i]--;
}
dist[0]=0;
while(k--){
ll e;
cin>>e;
e--;
dist[b[e]]=min(dist[b[e]],dist[a[e]]+c[e]);
}
if(dist[n-1]!=inf){
cout<<dist[n-1]<<"\n";
}
else cout<<-1<<endl;
return 0;
}
```