【解题报告】Codeforces Round #362 (Div. 2)
2016-07-15 17:08
489 查看
题目链接
如果 d=0 的话,直接在 a 的末尾加 b 个 0 输出。
否则如果结果是整数的话在 a 的末尾加上数量比 b 小的 0 输出。
否则将小数点移动后依次输出新的 a ,小数点和新的 d 。
d[i]=1−d[i−1]2
因为要得到最最简分数形式的概率,因此光得到递推公式是不够的,我们要求一个能直接计算出结果的封闭形式。于是用待定系数法可以得到一个等比数列的递推公式
d[i]−13=−12(d[i−1]−13)
解这个递推公式得
d[n]=(−1)n+2n−13×2n−1
凑巧的是,(−1)n+2n−1 正好是 3 的倍数(与 2 的幂的相邻的两个数中一定有一个是 3 的倍数)而且(−1)n+2n−1除以 3 一定能得到奇数,这样就能与上式分母的偶数互质了。所以有
p=(−1)n+2n−13
q=2n−1
题目就得解了。另外要注意的是,对分数取 mod 的时候要对分母计算模逆元,也就是要算出 3 的模逆元。计算 2n−1 的时候可以用快速幂算法来算。
最后,偶然发现像P这样的数被称为 Jacobsthalnumbers (维基百科)。
(其它题目略)
A. Pineapple Incident(Codeforces 697A)
思路
由于菠萝乱叫的时间点满足 t+p×s 或 t+q×s+1 ,其中 p≥0,q>0 。先判断 x=t 和 x=t+1 是否满足 ,如果不满足的话,我们就可以将 p,q 统一看成 k ,判断是否存在 k 使得 t+k×s=x 或 t+k×s+1=x,k≥0 。只要判断 (x−t)mods=0 或 (x−t)mods=1 是否满足即可。代码
#include <bits/stdc++.h> using namespace std; int t, s, x, tmp; int main() { cin >> t >> s >> x; tmp = (x - t) % s; if(x < t) { puts("NO"); } else if(x == t + 1) { puts("NO"); } else if(tmp == 0 || tmp == 1) { puts("YES"); } else { puts("NO"); } return 0; }
B. Barnicle(Codeforces 697B)
思路
本题的逻辑如下:如果 d=0 的话,直接在 a 的末尾加 b 个 0 输出。
否则如果结果是整数的话在 a 的末尾加上数量比 b 小的 0 输出。
否则将小数点移动后依次输出新的 a ,小数点和新的 d 。
代码
#include <bits/stdc++.h> using namespace std; int b, p, q; string l, r, s, sa, sd; stringstream ss; int main() { cin >> s; p = s.find('.'); q = s.find('e'); s[p] = s[q] = ' '; ss << s; ss >> sa >> sd >> b; if(sd == "0") { for(int i = 0; i < b; i++) { sa.push_back('0'); } cout << sa << endl; } else if(b >= sd.size()) { sa += sd; for(int i = 0; i < b - sd.size(); i++) { sa.push_back('0'); } cout << sa << endl; } else { l = sa + sd.substr(0, b); r = sd.substr(b, sd.size() - b); cout << l << '.' << r << endl; } return 0; }
C. Lorenzo Von Matterhorn(Codeforces 697C)
思路
修改 u−v 路径的权值的时候暴力找到 u 和 v 的最近公共祖先,边找边用 map 更新当前点的出边的权值。查找 u−v 路径的权值的时候暴力找到 u 和 v 的最近公共祖先,边找边累加当前点的出边的权值。代码
#include <bits/stdc++.h> using namespace std; typedef long long ll; int q, o; ll u, v, w, ans; map <ll, ll> mp; int main() { cin >> q; while(q--) { cin >> o >> u >> v; if(u < v) { swap(u, v); } if(o == 1) { cin >> w; while(u != v) { mp[u] += w; u >>= 1; if(u < v) { swap(u, v); } } } else { ans = 0; while(u != v) { ans += mp[u]; u >>= 1; if(u < v) { swap(u, v); } } cout << ans << endl; } } return 0; }
D. Puzzles(Codeforces 697D)
思路
如果想以树的节点编号做状态来做树形动态规划的话,对于每个节点,都要枚举子节点的访问顺序。这样的复杂度太高了。所以我们转而用公式法或者贡献度法来解决。对于一个点 v , strarttime[v] 显然等于先于 v 访问的节点的个数加上 1 。那么每个点 u 对点 starttime[v] 期望的贡献度就是 u 先于 v 访问的概率 pu 。那么 starttime[v] 的期望为∑pu+1。下面就考察每个点先于 v 访问的概率。首先对于 v 的祖先 u1,pu1=1 ,其次对于 v 的子树上的节点 u2,pu2=0 。最后对于其它所有节点 u3,pu3=0.5 (因为在 v 和 u3 的最近公共祖先的时候,往这两个节点所在的子树走的概率是相等的)。现在问题就转化成如何计算 u3 的数量。设 v 在树中的深度为 d[v] (根节点深度为 0 ), v 的子树的节点个数为 c[v] ,那么 u3 的数量就是 n−c[v]−d[v] 。因此答案就是n−c[v]−d[v]2+d[v]+1代码
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; int n, p, ans, c[maxn], d[maxn]; vector <int> G[maxn]; void dfs(int u) { c[u] = 1; for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; d[v] = d[u] + 1; dfs(v); c[u] += c[v]; } } int main() { scanf("%d", &n); for(int i = 2; i <= n; i++) { scanf("%d", &p); G[p].push_back(i); } dfs(1); for(int i = 1; i <= n; i++) { ans = n - c[i] + d[i] + 2; printf("%d.", ans / 2); printf(ans & 1 ? "5 " : "0 "); } puts(""); return 0; }
E. PLEASE(Codeforces 697E)
思路
因为这是一个概率问题,所以先按照状态转移的思想来思考。如果将初始状态定义为 (1,2,3) ,那么状态空间将只有 6 个元素—— (1,2,3),(1,3,2),(2,1,3),(2,3,1),(3,1,2),(3,2,1) 。但是将状态转移图画好后又会发现没有什么我们需要的线索。那么换一种状态定义方式呢?假设状态 i 为 i 次交换后的状态,令 d[i] 为 i 次交换后初始状态下的中间的杯子(我们可以暂时称之为第 2 个杯子)依然在中间的概率。我们试图寻找 d[i] 与 d[i−1] 的关系。不难发现,当状态为 i−1 时第 2 个杯子在中间的话,到了状态为 i 的时候第 2 个杯子就不可能在中间了。于是有如下关系d[i]=1−d[i−1]2
因为要得到最最简分数形式的概率,因此光得到递推公式是不够的,我们要求一个能直接计算出结果的封闭形式。于是用待定系数法可以得到一个等比数列的递推公式
d[i]−13=−12(d[i−1]−13)
解这个递推公式得
d[n]=(−1)n+2n−13×2n−1
凑巧的是,(−1)n+2n−1 正好是 3 的倍数(与 2 的幂的相邻的两个数中一定有一个是 3 的倍数)而且(−1)n+2n−1除以 3 一定能得到奇数,这样就能与上式分母的偶数互质了。所以有
p=(−1)n+2n−13
q=2n−1
题目就得解了。另外要注意的是,对分数取 mod 的时候要对分母计算模逆元,也就是要算出 3 的模逆元。计算 2n−1 的时候可以用快速幂算法来算。
最后,偶然发现像P这样的数被称为 Jacobsthalnumbers (维基百科)。
代码
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod = 1e9 + 7; bool one = true; int k, odd = 1; ll a, p, q = 2; // 快速幂算法 ll modPow(ll a, ll n, ll mod) { ll ans = 1; for(; n > 0; n >>= 1) { if(n & 1) { ans = (ans * a) % mod; } a = (a * a) % mod; } return ans; } // 求模逆元 ll modInv(ll a, ll mod) { return modPow(a, mod - 2, mod); } int main() { scanf("%d", &k); for(int i = 0; i < k; i++) { scanf("%I64d", &a); odd &= (a & 1); q = modPow(q, a, mod); if(a > 1) { one = false; } } q = (q * modInv(2, mod)) % mod; if(one == true) { p = 0; } else { p = q; p += (odd ? -1 : 1); p = (p * modInv(3, mod)) % mod; } printf("%I64d/%I64d\n", p, q); return 0; }
(其它题目略)
相关文章推荐
- Codeforces Round #197 (Div. 2)
- Codeforces Round #198 (Div. 1)
- Codeforces 405E Codeforces Round #238 (Div. 2)E
- Codeforces 407C Codeforces Round #239 (Div. 1)C
- HDU 1000
- HDU 1001
- CodeForces 449A - Jzzhu and Chocolate
- CodeForces 449 B. Jzzhu and Cities
- codeforces 618C. Constellation
- Codeforces Round #349 (Div. 2) - C
- Codeforces Round #361 (Div. 2)
- 7.13Codeforces Round #360 (Div. 2)
- Codeforces Round #265 (Div. 2)
- Codeforces #310 div2 C. Case of Matryoshkas
- 状态压缩DP codeforces 244 Problem C. The Brand New Function 和 codeforces 165 E. Compatible Numbers
- codeforces 16 Problem E fish
- Codeforces Round332 部分题解
- POJ 1979
- CodeForces 603A_Alternative Thinking (DP)
- CodeForces 602B_Approximating a Constant Range_DP