# 2022 01/09 APCS 題解
## [程式交易](https://zerojudge.tw/ShowProblem?problemid=h081)
存兩個變數 : 現在手上有沒有股票和上一次交易金額
然後暴搜
$O(N)$
```cpp=
#include <bits/stdc++.h>
using namespace std;
signed main(){
int n, d, hav = 1, lst, p, ans = 0;
cin >> n >> d >> p;
lst = p;
for(int i = 1; i < n; i++){
cin >> p;
if(hav * (p - lst) >= d){
if(hav > 0) ans += p - lst;
hav *= -1;
lst = p;
}
}
cout << ans << "\n";
return 0;
}
```
## [贏家預測](https://zerojudge.tw/ShowProblem?problemid=h082)
開vector存現在場上的人,遞迴下去暴搜
$O(NM)$
```cpp=
#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
int m;
array<int, 1004> S, T, los;
int fight(vector<int> &P){
if(P.size() == 1) return P[0];
int a, b, tmp;
vector<int> W, F;
for(int i = 0; i < P.size(); i += 2){
if(i + 1 >= P.size()){
W.pb(P[i]);
continue;
}
a = P[i], b = P[i + 1];
if(S[a] * T[a] < S[b] * T[b]) swap(a, b);
tmp = S[a];
S[a] += (S[b] * T[b]) / (T[a] << 1);
T[a] += (S[b] * T[b]) / (tmp << 1);
S[b] += S[b] >> 1;
T[b] += T[b] >> 1;
los[b]++;
W.pb(a), F.pb(b);
}
for(int f : F){
if(los[f] >= m) continue;
W.pb(f);
}
return fight(W);
}
signed main(){
int n, p;
vector<int> P;
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> S[i];
for(int i = 1; i <= n; i++) cin >> T[i];
for(int i = 0; i < n; i++){
cin >> p;
P.pb(p);
}
cout << fight(P) << "\n";
return 0;
}
```
## [數位占卜](https://zerojudge.tw/ShowProblem?problemid=h083)
先對每個字串做前綴 hash ,然後把整個字串的 hash value 丟進 set 裏面
接著枚舉每個字串,再對每個字串暴搜籤的一半長度,然後檢查該字串的前綴和後綴是否相同(這邊會用到模逆元),然後再拿中間的子字串去 set 裏面找有沒有跟他一樣的字串就可以判斷能不能構成「允籤」了
$O(MlenlogM)$
HASH :
把一個字串變成數字
$abcde \ \implies \ ax^0 + bx^1 + cx^2 + dx^3 + ex^4$
其中 $x$ 可以是任何大於字母範圍的數字
且由於 hash value 可能會過大,變數存不下,所以通常都會拿去模一個很大但是塞得下的數字
$abcde \ \implies \ (ax^0 + bx^1 + cx^2 + dx^3 + ex^4) mod \ m$
通常 $x$ 和 $m$ 都會選擇質數,比較不容易發生不同字串 hash 出來長一樣的問題
模逆元 :
根據費馬小定理
$p$ 為質數,則 $x^{p - 1} \equiv 1 (mod \ p)$,$x$ 可為任何數
因此 $x^{p - 2}$ 就相當於 $\frac{1}{x}$
```cpp=
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 2147483647;
array<int, 104> C, I;
array<string, 50004> S;
array<array<int, 104>, 50004> H;
array<set<int>, 104> Z;
int pow(int x, int k){
int ans = 1;
for(int i = 1; i <= k; i <<= 1){
if(i & k) ans = ans * x % mod;
x = x * x % mod;
}
return ans;
}
void build(int n){
C[0] = I[0] = 1;
for(int i = 1; i <= n; i++){
C[i] = 29 * C[i - 1] % mod;
I[i] = pow(C[i], mod - 2);
}
}
void hsah(string &s, int p){
int n = s.size();
H[p][0] = s[0] - 'a' + 1;
for(int i = 1; i < n; i++){
H[p][i] = (H[p][i - 1] + (s[i] - 'a' + 1) * C[i]) % mod;
}
Z[n].insert(H[p][n - 1]);
}
int see(int p, int l, int r){
if(!l) return H[p][r];
return ((H[p][r] - H[p][l - 1] + mod) % mod) * I[l] % mod;
}
int match(int m){
int ans = 0, n;
for(int i = 0; i < m; i++){
n = S[i].size();
for(int j = 1; j < n; j++){
if(2 * j <= n) continue;
if(see(i, 0, n - j - 1) == see(i, j, n - 1)){
if(Z[2 * j - n].find(see(i, n - j, j - 1)) != Z[2 * j - n].end()) ans++;
}
}
}
return ans;
}
signed main(){
int m;
cin >> m;
build(101);
for(int i = 0; i < m; i++){
cin >> S[i];
hsah(S[i], i);
}
cout << match(m) << "\n";
return 0;
}
```
## [牆上海報](https://zerojudge.tw/ShowProblem?problemid=h084)
對值域二分搜,看海報最高能貼多高
$O((N + K)logC)$
```cpp=
#include <bits/stdc++.h>
using namespace std;
array<int, 50004> W;
array<int, 200004> H;
int post(int n, int h){
int con = 0, cnt = 0;
for(int i = 0; i < n; i++){
if(!W[cnt]) break;
if(H[i] >= h) con++;
else con = 0;
if(con >= W[cnt]){
con = 0;
cnt++;
}
}
return cnt;
}
int BIS(int n, int k){
int l = 0, r = 1e9, mid;
while(l != r){
mid = ((l + r) >> 1) + 1;
if(post(n, mid) < k) r = mid - 1;
else l = mid;
}
return l;
}
signed main(){
int n, k;
cin >> n >> k;
for(int i = 0; i < n; i++) cin >> H[i];
for(int i = 0; i < k; i++) cin >> W[i];
cout << BIS(n, k) << "\n";
return 0;
}
```