# 112上學期第二次社內賽題解 ## 四則運算 照題目做就好了 ```cpp= #include<bits/stdc++.h> using namespace std; int n; vector<int> de, in; int main(){ cin >> n; for(int i=0, a, b; i<n+1; i++){ cin >> a >> b; de.push_back(a*b); in.push_back(a/(b+1)); } cout << "a(x)=\n"; for(int i=0; i<de.size()-1; i++) cout << de[i] << ' ' << n-i-1 << '\n'; if(de.size()==1) cout << "0 0\n"; cout << "A(x)=\n"; for(int i=0; i<in.size(); i++) cout << in[i] << ' ' << n-i+1 << '\n'; cout << "c 0\n"; } ``` ## 救救牛奶糖 三層迴圈硬幹 這樣是 $O(n^3)$,但其實可以壓到 $O(n^2)$,~~但是我懶~~ 可以想想要怎麼改會變成 $O(n^2)$ ```cpp= #include<bits/stdc++.h> using namespace std; int n, x, y, z; int main(){ cin >> n >> x >> y >> z; for(int i=0; 2*i<=n; i++){ for(int j=0; 2*i+3*j<=n; j++){ for(int k=0; 2*i+3*j+4*k<=n; k++){ if(2*i+3*j+4*k==n) cout << i << ' ' << j << ' ' << k << ' ' << i*x+j*y+k*z << '\n'; } } } } ``` ## 和乘數 [題目來源](https://atcoder.jp/contests/arc165/tasks/arc165_a?lang=ja) $A$ 是大於等於 $2$ 的正整數 我們可以分兩部分討論 1. **$A$ 是某個質數的乘冪** 若 $A$ 為某個質數的乘冪,則可以令 $A=p^e$,其中 $p$ 為質數,$e$ 為正整數 注意到,要分成兩個以上的正整數並且這些正整數的公倍數為 $A$ 即 $x_i<A$ 且 $x_i|A$ 有此可知 $x_i$ 一定是 $p^k(k<e)$,如此一來 $x_i|p^{e-1}$ 也就是說這些數的最小公倍數最多就是 $p^{e-1}$ 因此這樣的 $A$ 不是和乘數 2. **$A$ 不是某個質數的乘冪** 若是如此,則 $A$ 一定存在相異質因數 $p, q$ $(p\not=q)$ 令 $k=A-\frac{A}{p}-\frac{A}{q}(\ge A-\frac{A}{2}-\frac{A}{3}=\frac{A}{6}>0)$ 則我們一定能將 $A$ 分成 $k+2$ 個數 $(x_1, x_2, \cdots, x_k, x_{k+1}, x_{k+2})=(1, 1, \cdots, 1, \frac{A}{p}, \frac{A}{q})$ 因此這樣的 $A$ 是和乘數 得知了這樣的結果,我們就可以簡單的去看每個 $A$ 是不是某個質數的乘冪(即是否有兩個以上的相異質因數),用 $O(\sqrt{A})$ 去做類似質因數分解的事就好了 總時間複雜度 $O(N\sqrt{A})$ ```cpp= #include<bits/stdc++.h> using namespace std; int n, a; long long ans=0; // 記得開 long long int main(){ cin >> n; while(n--){ cin >> a; int tmp=a; for(int i=2; i<=sqrt(a); i++){ if(tmp%i==0){ while(tmp%i==0) tmp/=i; if(tmp!=1) ans+=a; // 把一個質因數全部去掉後還有其他質因數 break; } } } cout << ans; } ``` ## 好大的黑板 令 $f(x)$ 為 $x$ 可以得到最大的乘積 則我們可以寫出遞迴式 \begin{cases} f(1)=1 \\ f(x)=\max\{x, f(\lfloor\frac{x}{2}\rfloor)f(\lceil\frac{x}{2}\rceil)\}, x\ge 2 \end{cases} 而再觀察一下則會發現 當 $x\le 4$ 時,$f(x)=x$ 當 $x\ge 5$ 時 $f(\lfloor\frac{x}{2}\rfloor)f(\lceil\frac{x}{2}\rceil)\ge \lfloor\frac{x}{2}\rfloor\lceil\frac{x}{2}\rceil\ge \frac{x-1}{2}\cdot\frac{x}{2}=\frac{x-1}{4}\cdot x\ge x$ 因此 $f(x)=f(\lfloor\frac{x}{2}\rfloor)f(\lceil\frac{x}{2}\rceil)$ 所以整理一下可以得到 \begin{cases} f(x)=x, x\le 4 \\ f(x)=f(\lfloor\frac{x}{2}\rfloor)f(\lceil\frac{x}{2}\rceil), x\ge 5 \end{cases} 然後再做遞迴就好了 不過這題數字很大,可能會一直算到重覆的數字,那就會 TLE 我們可以先把已經算過的數字存起來,之後再碰到它就可以直接用(~~絕對不是dp~~) C++ 用 map,python 用 dictionary ```cpp= #include<bits/stdc++.h> using namespace std; long long x; const int MOD=998244353; unordered_map<long long, long long> memo; long long slv(long long a){ if(memo.count(a)) return memo[a]; if(a<=4) return memo[a]=a; return memo[a]=slv(a/2)*slv((a+1)/2)%MOD; } int main(){ cin >> x; cout << slv(x); } ```