元宵爆零赛
闫神的元宵欢乐爆零赛,全场2/3爆零啦...
好吧其实是我太菜,才讲的原题都不会。
T1 树上游走(tree)
【题目描述】
有一棵n个点的树。
有m次询问,每次给定起点s和终点t,会从s走到t。由于眼神不好,它会按如下方式走路:
(1)初始时在s,如果到达t就立刻停止;
(2)如果相邻点中存在离s更远且没走过的点,那么等概率随机一个满足条件的点走过去;
(3)否则,往s所在方向走一步。
你需要求出期望经过多少个点(包括s和t)。一个点被多次经过只计算一次。
【输入数据】
第一行两个整数n,m,接下来n-1行每行两个整数u,v表示一条边,接下来m行每行两个整数s,t表示一组询问。
【输出数据】
每组询问输出一行一个实数表示答案,保留一位小数。
【样例输入】
3 2
1 2
2 3
1 2
1 3
2 3
【样例输出】
2.0
3.0
2.5
【数据范围】
对于10%的数据,n,m<=7。
对于30%的数据,n,m<=100。
对于60%的数据,n<=5000。
对于100%的数据,1<=n,m<=500000,s!=t。
【题解思路】
推一下样例会发现样例第三个询问好像跟我们预想的不大一样,预想0.5*(1+1)+1*(1+0.5*(1+1))=3,实际0.5*(1+1+1)+0.5*(1+1)=2.5;诶这个0.5是乘在外面的诶...
这是一颗树,那么从s到t的最短路径是唯一的,无论怎么走,都要走遍s到t的树上最短路径,假若在任何时刻走到了s到t的最短路的节点上,它会随机一个点走下去,等价于求儿子的全排列哇...
假如此时走到了x,选择了一个不是s到t最短路径上的节点,然后遍历其整个子树之后必然要回去原来的x节点,以此往返,因此就相当于找一个儿子排列来走。从s到t的路径上的点与其等深度的点有同等几率被走到,当走到了s到t路径上点时停止遍历子树而又返回的操作。这个排列以一个在s到t路径上的点为开始,以另一个在s到t的路径上的点结束,对于不在s到t路径上的点,都有1/2的几率(等概率随机选择,有或无)出现在这个排列之中。
【code】
#include<bits/stdc++.h> using namespace std; int read(){ int x = 0, w = 0; char ch = 0; while (!isdigit(ch)) {w |= ch == '-'; ch = getchar();} while (isdigit(ch)) {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar();} return w ? -x : x; } int a[500010], n, m, deep[500010], f[21][500010]; vector<int> v[500010]; int p; void dfs(int x){ for (int i = 1; i <= 20; ++i) f[i][x] = f[i - 1][f[i - 1][x]]; a[x] = 1; for (int i = 0; i < v[x].size(); ++i) if (v[x][i] != f[0][x]) { f[0][v[x][i]] = x; deep[v[x][i]] = deep[x] + 1; dfs(v[x][i]); a[x] += a[v[x][i]]; } } int LCA(int x, int y){ if (deep[x] < deep[y]) swap(x, y); if (deep[x] > deep[y]){ for (int i = 20; ~i; --i) if (deep[x] - (1 << i) > deep[y]) x = f[i][x]; if (f[0][x] == y){ p = x; return y; } x = f[0][x]; } for (int i = 20; ~i; --i) if (f[i][x] != f[i][y]) x = f[i][x], y = f[i][y]; return f[0][x]; } int main(int argc, char const *argv[]) { freopen("tree.in", "r", stdin); freopen("tree.out", "w", stdout); n = read(), m = read(); for (int i = 1; i < n; ++i) { int x = read(), y = read(); v[x].push_back(y); v[y].push_back(x); } deep[1] = 1; dfs(1); while (m--) { int s = read(), t = read(), g, k; int lca = LCA(s, t); if (lca == t) k = n - a[p] - 1; else k = a[t] - 1; g = n + (deep[s] + deep[t] - 2 * deep[lca] + 1) - k; printf("%d.%d\n", g / 2, g % 2 * 5); } return 0; }
T2最小质因数(prime)
【题目描述】
精通数数,它想让你帮他算出[1,n]中所有合数的最小质因数的k次方和。
【输入数据】
一行两个整数n,k。
【输出数据】
输出一行一个整数表示答案。对264取模。
【样例输入1】
10 1
【样例输出1】
11
【样例输入2】
10 2
【样例输出2】
25
【数据范围】
对于20%的数据,n<=108。
对于60%的数据,n<=1010。
对于100%的数据,1<=n<=2*1011,1<=k<=109。
数据有梯度。
【题解思路】
20分:看似很送分的线性筛,你要试看看开3个1e8的数组吗...
60分?:对于x<=k的情况,进行常见的枚举子集容斥;对于x>k的情况,n/x较小,在n/k的范围内进行线性筛/埃氏筛法。(如何确定这个k值,优秀一点的可能会有意想不到的收获)
100分:进行子集容斥时,枚举子集后贡献形如(-1)i(n/S),而n/S只有O(sqrt(n))种取值,对这个进行记忆化即可。
【code】传送门
T3路径(path)
【题目描述】
有一张n个点m条边的无向连通图,它想知道有多少条长度不小于k的简单路径。
【输入数据】
第一行三个整数n,m,k,接下来m行每行两个整数表示一条边。
【输出数据】
输出一行一个整数表示答案。
【样例输入】
5 5 2
1 3
2 4
3 5
4 1
5 2
【样例输出】
20
【数据范围】
对于20%的数据,n<=2000。
对于另外50%的数据,m=n-1。
对于100%的数据,1<=k<=n<=100000,n-1<=m<=n。
【题解思路】本题同【BZOJ3648】寝室管理
【code】上面的一行变成超链接的时候,就有代码可以看了
(总而言之就是ve又挖坑了。。。