比赛链接:https://atcoder.jp/contests/abc160/tasks
AtCoder Beginner Contest 160
A - Coffee

#include <bits/stdc++.h> using namespace std; int main() { string s;cin>>s; cout<<(s[2]==s[3]&&s[4]==s[5]?"Yes":"No"); return 0; }
B - Golden Coins

#include <bits/stdc++.h> using namespace std; int main() { int x;cin>>x; cout<<(x/500*1000+x%500/5*5); return 0; }
C - Traveling Salesman around Lake
题意:环形池塘的一周坐落着几户人家,问以一户为起点拜访完所有人家的最短路程 。
思路:对于最短路程来说,无论是顺时针还是逆时针都不会改变,所以按照题目给出的顺时针顺序两两相减即可,差小于零代表着逆时针需要走的路程,加上一个圆周即是顺时针需要走的路程。

#include <bits/stdc++.h> using namespace std; int main() { int k,n;cin>>k>>n; int a[n];for(int &i:a) cin>>i; int mi=numeric_limits<int>::max(); for(int i=0;i<n;i++) mi=(mi,a[(i+n-1)%n]-a[i]+k)%k; cout<<mi; return 0; }
D - Line++
题意:一条链中再有不相邻两点相连,问最短距离为1~N-1的点对各有多少。
思路:BFS得到每个点到其他点的最短距离。

#include <bits/stdc++.h> using namespace std; const int M=2200; vector<int> e[M]; int dis[M][M],ans[M]; void bfs(int st){ queue<int> q; dis[st][st]=1; q.push(st); while(!q.empty()){ int u=q.front(); q.pop(); for(int v:e[u]) if(dis[v][st]==0){ dis[v][st]=dis[u][st]+1; q.push(v); } } } int main(){ int n,x,y;cin>>n>>x>>y; for(int i=0;i<n-1;i++){ e[i].push_back(i+1); e[i+1].push_back(i); } --x,--y; e[x].push_back(y); e[y].push_back(x); for(int i=0;i<n;i++) bfs(i); for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) ++ans[dis[i][j]-1]; for(int i=1;i<n;i++) cout<<ans[i]<<"\n"; return 0; }
E - Red and Green Apples
题意:有A个红苹果,B个绿苹果,C个无色苹果(可以当作红苹果或绿苹果),每个苹果有一个可口度,若要吃掉X个红苹果,Y个绿苹果(X≤A,Y≤B),问最大可口度之和。
思路:取A中X个较可口的红苹果,B中Y个较可口的绿苹果,如C中有更可口的无色苹果替换之。

#include <bits/stdc++.h> using namespace std; int main(){ int x,y,a,b,c;cin>>x>>y>>a>>b>>c; vector<int> v1(a),v2(b),v3(c); for(int &i:v1) cin>>i; for(int &i:v2) cin>>i; for(int &i:v3) cin>>i; sort(v1.rbegin(),v1.rend()); sort(v2.rbegin(),v2.rend()); for(int i=0;i<x;i++) v3.push_back(v1[i]); for(int i=0;i<y;i++) v3.push_back(v2[i]); sort(v3.rbegin(),v3.rend()); cout<<accumulate(v3.begin(),v3.begin()+x+y,0LL); return 0; }
F - Distributing Integers
参考了 BakaCirno 、tttttttttrx 两位大大的博客。
题意:给一棵 $n$ 点树染色,每次只能选择与已染色结点相邻的未染色结点,所用颜色依次为 $1 \sim n$,问以每个结点为起点时的染色情况总数。
思路:$n$ 个点染色的全排列情况为 $n!$,对于一棵树中的每棵子树,它的根一定要在这棵子树的排列的第一个,即该棵子树的排列中只有 $\frac{1}{size}$ 个是合法的,那么所有排列中就只有 $\frac{1}{\prod_{u=1}^{n}{size[u]}}$ 种是合法的,答案即 $\frac{n!}{\prod_{u=1}^{n}{size[u]}}$ 。
之后考虑如何换根,假设已经得到以 $fa$ 为根的答案,考虑结点 $fa$ 和它的一个子结点 $son$:
$ans[fa] = \frac{n!}{n\ *\ size[son]\ *\ size[x]}$,$n$ 即 $size[fa]$,$size[x]$ 是除父子结点外所有子树的合法情况。
因为以二者为根的两棵树中,相差的只有以另一方为子树根的 $size$ 数,其他的子树结点都是相同的,如果根为 $fa$,以 $son$ 为子树根的子树大小为 $size[son]$,那么根为 $son$,以 $fa$ 为子树根的子树大小即为 $n\ -\ size[son]$,由此可以求得:
$ans[son] = \frac{n!}{n\ *\ size[n\ -\ size[son]]\ *\ size[x]}$
据此,我们先算出一个点的答案,然后在从该点出发遍历树的过程中递推出所有子结点的答案。

#include <bits/stdc++.h> using LL = long long; using namespace std; const int M = 2e5 + 100; const int mod = 1e9 + 7; vector<int> e[M]; int n, sz[M], ans[M]; int fac[M], inv[M]; LL mul(LL a, LL b) { return a * b % mod; } void init() { fac[0] = 1; for (int i = 1; i <= n; i++) fac[i] = mul(fac[i - 1], i); inv[1] = 1; for (int i = 2; i <= n; i++) inv[i] = mul((mod - mod / i), inv[mod % i]); } void dfs(int u, int fa) { sz[u] = 1; for (int v : e[u]) { if (v != fa) { dfs(v, u); sz[u] += sz[v]; } } } void reroot(int u, int fa) { ans[u] = mul(mul(ans[fa], sz[u]), inv[n - sz[u]]); for (int v : e[u]) { if (v != fa) { reroot(v, u); } } } int main() { cin >> n; init(); for (int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; e[u].push_back(v); e[v].push_back(u); } dfs(1, 0); ans[1] = fac[n]; for (int i = 1; i <= n; i++) ans[1] = mul(ans[1], inv[sz[i]]); for (int v : e[1]) reroot(v, 1); for (int i = 1; i <= n; i++) cout << ans[i] << "\n"; }