qbxt国庆水题记day2
来源:互联网 发布:windows c盘清理 编辑:程序博客网 时间:2024/05/27 03:27
qbxt国庆水题记
day2
//100 + 0 + 0 = 100
//除了超水题以外其他的都不会
Problem 1. video
Input file: video.in
Output file: video.out
Time limit: 1s
Memory limit: 256M
pluto 喜欢看片,现在他的硬盘里有 n 部片,但是由于他还要把妹,所以看片时间有限,他只能挑出
其中的 k 部片来看,他想知道有多少种不同的选片方案。方案数可能很大,答案 mod 1000000007 输出。
Input
输入文件第一行一个整数 N, 表示这个星球上的总人口。
接下来 N 行,每行一个正整数,表示每个居民的姓名。
Output
输出文件一行一个整数,表示这个星球的价值。
Example
video.in
6 2
video.out
15
Scoring
• 对于 30% 的数据,n ≤10
• 对于 60% 的数据,n ≤3000
• 对于 100% 的数据,n ≤2 ×105
排列组合
根据公式求阶乘,在求下逆元即可
代码
#include<iostream>#include<cstdio>using namespace std;#define ll long longconst int inf = 1000000007;int n,m;ll p,q;void exgcd(ll a,ll b,ll &d,ll &x,ll &y) { if(!b) {d = a, x = 1, y = 0;return;} exgcd(b,a%b,d,y,x); y -= x * (a / b);}ll inv(ll a, ll b) { ll d,x,y; exgcd(a,b,d,x,y); return (x % b + b) % b;}int main() { freopen("video.in","r",stdin); freopen("video.out","w",stdout); cin>>n>>m; m = min(m, n-m); p = 1, q = 1; for(int i = 1; i <= m; i++) p = (p * i) % inf; q = inv(p,inf); for(int i = n; i >= n - m + 1; i--) q = (q * i) % inf; cout<<q<<endl; return 0;}
Problem 2. chance
Input file: chance.in
Output file: chance.out
Time limit: 1s
Memory limit: 256M
pluto 去找妹子 ×××约会,然后×××要求和 pluto 玩一个游戏,pluto 赢了才能获得和 ×××
约会的机会。游戏内容为:现在有 N 个袋子 (你可以认为它是哆啦 A 梦的口袋,每个袋里面放着一些
,所以容量十分大,第 i 个袋里面放着编号为 Li 到 Ri 的球 (除编号外完全相同),pluto 需要从每个
袋里面摸出一个球,第 i 个袋子任何一个球被摸到的概率是 1/(Ri −Li + 1),如果 pluto 摸出的球中
有 K% 或以上的球的编号的第一位是 1(比如 11,121,199 的第一位是 1, 而 21,233 第一位就不是 1),那
么 pluto 就将赢得与 ×××约会的机会。现在 pluto 想知道他能人生中第一次与妹子约会的概率有多大。
Input
第一行两个整数 N, K
接下来 N 行,每个两个整数,Li 和 Ri
Output
一行一个实数(保留 7 位⼩数)表示答案
绝对误差不超过 10−6 即视为正确
Example
chance.in
2 50
1 2
9 11
chance.out
0.833333333333333
Scoring
• 对于 100% 的数据,0 ≤k ≤100,0 < Li ≤Ri
• 对于 30% 的数据,n ≤10,Li ≤Ri ≤100
• 对于 60% 的数据,n ≤500,Li ≤Ri ≤2000
• 对于 100% 的数据,n ≤2000,Li ≤Ri ≤1018
首先判断出每个袋子里拿到第一个数字为1的球的概率为pi(很巧妙的判断见”pd()”)
dp[i][j] 表示前i个袋子里取到了j个第一个数字为1的球的概率
dp[i][j] = dp[i - 1][j - 1] * pi + dp[i - 1][j] * (1 - pi)
然后根据K%求出至少要多少人,相加即可
//为什么这么多dp
//啊啊啊啊啊
代码
#include<iostream>#include<cstdio>#include<cmath>using namespace std;const int maxn = 2000 + 100;int n;long long l,r;double k,pi[maxn],f[maxn][maxn];long long pd(long long x) { long long num = 1,sum = 1; if(!x) return 0; for(int i = 2; i <= 20; i++) { num *= 10; if(num > x) return sum; if(num * 2 > x) return sum + x - num + 1; sum += num; }}int pp(double p) { if(p - (int)p == 0) return (int)p; else{ return (int)(p + 1); }}int main() { freopen("chance.in","r",stdin); freopen("chance.out","w",stdout); cin>>n>>k; for(int i = 1; i <= n; i++) { scanf("%lld%lld",&l,&r); pi[i] = (double)(pd(r) - pd(l-1)) / (double)(r - l + 1); } f[0][0] = 1; for(int i = 1; i <= n; i++) { for(int j = 0; j <= i; j++) { f[i][j] += f[i-1][j] * (1 - pi[i]); if(j) f[i][j] += f[i-1][j-1] * pi[i]; } } k /= 100; int t = pp(n*k); double ans = 0; for(int i = t; i <= n; i++) { ans += f[n][i]; } printf("%.7f\n",ans); return 0;}
Problem 3. plutotree
Input file: plutotree.in
Output file: plutotree.out
Time limit: 2s
Memory limit: 256M
有一棵 n 个节点的树,节点编号为 1 到 n,i 号节点的权值为 Wi。这棵树有些奇怪,它的每一个
叶子节点都是根节点的夫亲 (表示每个叶子节点与根节点之间有一条边权为 0 的边)。我们称这样的树为
pluto 树,根节点编号为 1。我们需要最小化从 u 到 v 的路径 (每条边只能经过一次) 上的节点权值之和,
并且在最小化节点权值之和的同时求这个路径上可能的最大权值。
Input
第一行两个整数 n 和 q,n 表示节点个数,q 表示询问个数。
第二行 n −1 个整数 Ai,表示 i + 1 号节点的夫亲为 Ai
第三行 n 个整数 Wi 表示 i 号节点的权值为 Wi
接下来 q 行,每行两个整数 u,v,表示一组询问
Output
对于每组询问输出两个整数 x, y
x 表⽰ u 到 v 的权值和最小的路径的权值和,y 表⽰这条路径上点权最大值。如果有多个相同权值
和的路径,输出那个点权最大值最大的。
Example
plutotree.in
5 1
1 2 3 4
413 127 263 869 960
1 5
plutotree.out
1373 960
Scoring
• 对于 30% 的数据,n ≤300,q ≤1000
• 对于 50% 的数据,n ≤2000,q ≤10000
• 对于 100% 的数据,n ≤100000,q ≤100000
//树上dp
//不会,暴力也不会打
来自题解
30% 把图建建出来 floyd
60% 把floyd换成spfa或者dijkstra
100% 树形dp
首先答案可能有三种情况:
1.不走叶子到根的边, 那就是一个简单的树上的问题, 两点之间有且仅有一条路径,树上倍增一下就可以把两个问题都解决, 或者闲着蛋疼的可以用树剖
2.从u走到叶子,从叶子到根,从根到v (这种情况要把u、v调换再做一次)
3.从u走到叶子,从叶子到根,从根到另一个叶子节点,再从叶子节点到v
对于第二种、三种情况, 其实关键在于求出每个点到离他最近的叶子的路径,这样的路径有两种可能,一种是向下下走到叶子, 一种是先向上(有可能经过根也可能不经过)走,最终到达叶子
首先树形dp出每个节点向下到离它最近的叶子节点的距离,并同时记录这个路径上的最大值,设为down[i], (down[i]为二元组,<路径权值和, 路径上最大权值>) down[i] 可以从 i号节点的所有儿子转移过来, 转移方程很显然
有了down[i], 就可以dp出我们需要的每个点到最近的叶子节点的路径了,将这个记为dp[i], dp[i]同样是一个二元组,和down[i]一样。 首先dp[1]我们是知道的,就是从根直接走到某一个叶子节点, 其余的dp[i]初值都是down[i], dp[i]可以从i号节点的父亲转移过来,所以这是一个自上而下的dp
考虑到可能爆栈的情况, 建议使用bfs处理树形dp
具体状态如何转移可以参考std
代码std
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;const int N = 111111;const int inf = 1 << 20;int fa[N][20], n, m, maximum[N][20], leaf[N], weight[N];int dist[N],dep[N];pair<int, int> dp[N], down[N];vector<int> adj[N];void update(pair<int, int> &x, pair<int, int> y) { if (x.first != y.first) { x = min(x, y); } else { x = max(x, y); }}void build() { vector<int> queue; queue.push_back(1); fa[1][0] = 0; dep[1] = 1; dist[1] = weight[1]; for (int head = 0; head < (int)queue.size(); head++) { int now = queue[head]; for (int i = 0; i < (int)adj[now].size(); i++) { queue.push_back(adj[now][i]); dep[adj[now][i]] = dep[now] + 1; dist[adj[now][i]] = dist[now] + weight[adj[now][i]]; } } for (int j = 1; j <= 18; j++) { for (int i = 1; i <= n; i++) { fa[i][j] = fa[fa[i][j - 1]][j - 1]; maximum[i][j] = max(maximum[i][j - 1], maximum[fa[i][j - 1]][j - 1]); } } for (int i = (int)queue.size() - 1; i >= 0; i--) { int x = queue[i]; update(down[fa[x][0]], make_pair(down[x].first + weight[fa[x][0]], max(down[x].second, weight[fa[x][0]]))); }}void DP() { vector<int> queue; queue.push_back(1); update(dp[1], down[1]); for (int head = 0; head < (int)queue.size(); head++) { int now = queue[head]; for (int i = 0; i < (int)adj[now].size(); i++) { int to = adj[now][i]; dp[to] = down[to]; update(dp[to], make_pair(dp[now].first + weight[to], max(weight[to], dp[now].second))); queue.push_back(to); } }}pair<int, int> query(int x, int y) { if (dep[x] < dep[y]) swap(x, y); int fx = x, fy = y; int maxd; int ret1 = 0, ret2 = 0; for (maxd = 0; (1 << maxd) <= dep[x]; maxd++); maxd--; ret1 = max(maximum[x][0], maximum[y][0]); for (int i = maxd; i >= 0; i--) { if (dep[fa[x][i]] >= dep[y]) { ret1 = max(ret1, maximum[x][i]); x = fa[x][i]; } } ret1 = max(ret1, maximum[x][0]); ret1 = max(ret1, maximum[y][0]); if (x == y) { ret2 = dist[fx] - dist[fy] + weight[fy]; return make_pair(ret1, ret2); } for (int i = maxd; i >= 0; i--) { if (fa[x][i] != 0 && fa[x][i] != fa[y][i]) { ret1 = max(ret1, maximum[x][i + 1]); ret1 = max(ret1, maximum[y][i + 1]); x = fa[x][i]; y = fa[y][i]; } } ret1 = max(ret1, maximum[x][0]); ret1 = max(ret1, maximum[y][0]); ret1 = max(ret1, maximum[fa[x][0]][0]); ret2 = dist[fx] + dist[fy] - dist[fa[x][0]] * 2 + weight[fa[x][0]]; return make_pair(ret1, ret2);}void add(int x, int y) { adj[x].push_back(y);}void solve() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) adj[i].clear(); for (int i = 1; i <= n - 1; i++) { int x; scanf("%d", &x); add(x, i + 1); fa[i + 1][0] = x; } for (int i = 1; i <= n; i++) { if (adj[i].size() == 0) leaf[i] = 1; else leaf[i] = 0; } for (int i = 1; i <= n; i++) { scanf("%d", &weight[i]); maximum[i][0] = weight[i]; } for (int i = 1; i <= n; i++) { dp[i] = make_pair(inf, 0); down[i] = make_pair(inf, 0); } for (int i = 1; i <= n; i++) { if (leaf[i]) { down[i] = make_pair(weight[i], weight[i]); update(dp[1], make_pair(weight[1] + weight[i], max(weight[1], weight[i]))); } } build(); DP(); for (int i = 1; i <= m; i++) { pair<int, int> tmp, ans; int u, v; scanf("%d%d", &u, &v); tmp = query(u, v); ans = make_pair(tmp.second, -tmp.first); tmp = make_pair(dp[u].first + dist[v], -max(dp[u].second, maximum[v][18])); ans = min(ans, tmp); tmp = make_pair(dp[v].first + dist[u], -max(dp[v].second, maximum[u][18])); ans = min(ans, tmp); tmp = make_pair(dp[u].first + dp[v].first + weight[1], -max(max(dp[u].second, dp[v].second), weight[1])); ans = min(ans, tmp); printf("%d %d\n", ans.first, -ans.second); } }int main() { freopen("plutotree.in", "r", stdin); freopen("plutotree.out", "w", stdout); int tests = 1; for (int i = 1; i <= tests; i++) { solve(); } return 0;}
- qbxt国庆水题记day2
- qbxt国庆水题记day1
- qbxt国庆水题记day3
- qbxt国庆水题记day4
- qbxt国庆水题记day5
- qbxt国庆水题记day6
- [qbxt考试Day2.T1] video
- Qbxt 模拟题 day2(am) T2 jian
- 2017国庆郑州集训Day2
- QBXT
- 国庆清北刷题冲刺班 Day2 上午
- 国庆清北刷题冲刺班 Day2 下午
- 题记
- 题记
- 题记
- 题记
- 题记
- 题记
- [HDU]4035 Maze 期望公式推导
- HTML轮播记住一定要导入两个包
- 自定义view自定义一个带箭头的圆形详解 加速 减速 变颜色
- Java连接数据库DBHelper增删改查[多条数据]
- java String stringbuilder stringbuffer
- qbxt国庆水题记day2
- 周末训练笔记(10.8)—hdu3016+poj2886
- 《个人理财》
- Android开发艺术探索__android动画深入分析(七)
- 当鼠标悬停在时,改变字体,旋转,
- 电脑网线水晶头接法图解
- 盒子模型
- UVALive-7267/UVALive-7261/UVALive-7269/UVALive-7263
- reflow&repaint