--- title: 'AtCoder Beginner Contest 266' disqus: hackmd --- AtCoder Beginner Contest 266 === [TOC] ## string [A - Middle Letter](https://atcoder.jp/contests/abc266/tasks/abc266_a) :::info 輸出中間那個數。 ::: ```csharp= #include <bits/stdc++.h> using namespace std; #define ll long long #define N 1e9 int main() { ios::sync_with_stdio(false); cin.tie(0); string s; cin>>s; cout<<s[s.size()/2]<<'\n'; return 0; } ``` ## mod [B - Modulo Number](https://atcoder.jp/contests/abc266/tasks/abc266_b) :::info x=n+k倍的MOD(998244353),所以加到變成正數,再模MOD。 k慢慢跑會TLE(次數至多=$10^{18}/MOD+1$),所以設定k每跑一次,k會變成前一次的k*2。 ::: ```csharp= #include <bits/stdc++.h> using namespace std; #define ll long long #define MOD 998244353 int main() { ios::sync_with_stdio(false); cin.tie(0); ll n; cin>>n; for(ll i=1;i<1000000000;i*=2){ if(n>MOD) break; n+=i*MOD; } cout<<(n-MOD)%MOD; return 0; } ``` ## dp [D - Snuke Panic (1D)](https://atcoder.jp/contests/abc266/tasks/abc266_d) :::info 開兩個陣列x[t]、a[t],記錄在t時刻的蟲座標及果實大小。 這題看起來就很dp[i][j] (前後位置有關),那就來嘗試用dp解吧! 先思考dp[i][j]如何定義 * 定義dp[i][j]是在位置為i、時刻為j時,所能吃到最大size的蟲。 i介於0~4、j 介於0~$10^5$,所以設定陣列大小為dp[5][n], 再來思考dp[i][j]可能由何者遞迴得到 1. dp[i][j-1]而得(站在原地一秒鐘) 2. dp[i-1][t-1]而得(往右走一步) 3. dp[i+1][t-1]而得(往左走一步) 最後把上面三個取max=dp[i][j]。 記得在dp[i][j]的時刻及位置可以吃到a[t]大小的蟲,要加上去。 最後所求=時刻為$10^5$,在每個位置所能吃到的最大size。 ::: :::danger 注意下面的code:t跟i不能顛倒,不然會產生吃了又吃的問題。 ::: ```csharp= #include <bits/stdc++.h> using namespace std; #define ll long long #define n 100010 ll t,x[n],a[n],dp[n]; int main() { ios::sync_with_stdio(false); cin.tie(0); ll maxi=0; ll dp[5][n]; for(ll i=1;i<5;i++) dp[i][0]=-1e18; ll N; cin>>N; for(ll i=0;i<N;i++){ cin>>t;//t->唯一的x[t]、a[t] cin>>x[t]>>a[t]; } for(ll t=1;t<=100000;t++){ for(ll i=0;i<5;i++){ dp[i][t]=dp[i][t-1]; if(i!=0)dp[i][t]=max(dp[i][t],dp[i-1][t-1]); if(i!=4)dp[i][t]=max(dp[i][t],dp[i+1][t-1]); } dp[x[t]][t]+=a[t]; } for(ll i=0;i<5;i++) maxi=max(maxi,dp[i][100000]); cout<<maxi<<'\n'; return 0; } ``` ## 遞迴 [E - Throwing the Die](https://atcoder.jp/contests/abc266/tasks/abc266_e) :::info 這題的關鍵在於構造遞迴關係式,我們來思考 1. 第1回合的期望值=f(1)=1*$\frac{1}{6}$+2*$\frac{1}{6}$+3*$\frac{1}{6}$+4*$\frac{1}{6}$+5*$\frac{1}{6}$+6*$\frac{1}{6}$+=3.5 2. 第2回合的期望值=f(2)=max(1,f(1))$\frac{1}{6}$+max(2,f(1))$\frac{1}{6}$+max(3,f(1)) $\frac{1}{6}$+max(4,f(1))*$\frac{1}{6}$+max(5,f(1))$\frac{1}{6}$+max(6,f(1))$\frac{1}{6}$+=4.25 (覺得骰子點數太少就再投一次, 期望拿到max(本次可能投擲的點數,投擲前一次的期望值)$\frac{1}{6}$點 3. 由2.可觀察出遞迴關係式:f(n)=max(i,f(n-1)),i=1~6 如果直接用f(n)下去遞迴到f(1)=3.5會發生一件事情:f(n)無法被確定,無法直接return f(n-1)(因為還要比大小)=>所以要先建表f(n)。 那不如反過來做,從x=1遞迴到x=n。 而從轉移式可知:我們只需要兩個變數紀錄f(n)、f(n-1)即可,所以開x,y分別記錄兩者,完整程式碼如下。 ::: :::danger 如何cout浮點數到小數點下第n位置: 利用cout<<fixed<<setprecision(10)<<數字/變數<<'\n'; ::: ```csharp= #include <bits/stdc++.h> using namespace std; #define ll long long #define max(p,q)((p)>(q)?(p):(q)) #define N 1e9 int main() { ios::sync_with_stdio(false); cin.tie(0); ll n; double x=3.5,y;//x=f(x),y=f(x-1) cin>>n; for(ll i=2;i<=n;i++){ y=0; for(ll j=1;j<=6;j++){ y+=max(j,x)/6; } x=y;//交換 } cout<<fixed<<setprecision(10)<<x<<'\n'; return 0; } ```