牛客算法周周练16

红包期望
链接:https://ac.nowcoder.com/acm/contest/11517/A
来源:牛客网

题目描述
众所周知,在过年的时候每家每户都会发红包,现在clccle和qn在一起抢*信红包,但是她们觉得这样没有意思,便开始了计算,如果当clccle和sqn为第k个抢红包的人时候,所抢到红包金额的期望是多少?(红包的大小在[0,2n/m]中均匀随机,特别的当红包的大小小于2n/m时,最后剩下的金额会被包入最后一个红包中)
输入描述:
第一行,三个整数,m,n,T分别表示有一个红包可以被m个人领取,而且红包的总金额是n,接下来有T次询问

接下来T行,每行一个整数k,表示clccle和qn抢红包的时候是第几位
输出描述:
共T行

每行一个整数,表示clccle和qn所得到的红包大小的期望
示例1
输入
复制
10 100 3
10
15
16
输出
复制
10
0
0
说明
请自行证明(才不是因为窝证明之后你们就能直接出正解了呢qwq)
备注:
对于全部数据

1<=m<=n<=1e18,1<=T<=50000

生活常识

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#define x first
//#define y second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef unsigned long long ULL;

inline int read(int out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 2010 + 10;
const int M = 3e6 + 10;
const int mod = 2333;
const int PP = 13331;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

signed main(){
	double n, m;
	int q;
	cin >> n >> m >> q;
	
	while(q --){
		int x;
		cin >> x;
		if (x < 1 || x > n)   cout << "0" << endl;
		else   cout << m / n << endl;
	}
	
	return 0;
}

死肥宅的冲分计划
链接:https://ac.nowcoder.com/acm/contest/11517/B
来源:牛客网

题目描述
国庆十天假,死肥宅选择回家休息,休息期间死肥宅开始了他的召唤师峡谷冲分之旅,冲分之前死肥宅向其他队员打赌十天内必上王者,已知死肥宅初始段位为黄金,因为死肥宅是游戏鬼才,所以他可以控制每天的段位变化不会超过一个大段,每天都会有队员查看下死肥宅的段位,如果死肥宅上了一个大段那么就会在小本本上记一个1,如果大的段位没有变化那么就会在小本本上记一个0,如果掉了一个大段,那么就记一个7,但是存在一些特殊情况使得队员记录的数字代表的意义会发生一些改变(详情可看备注)十天后,我们可以得到一个10个数字的序列,试着根据这串序列算出死肥宅是否上了王者,如果死肥宅成功的话那么请输出“666”,否则请输出“777"。

输入描述:
多组输入,每行输入10个数字,只包含1,0,7,三个数字。
输出描述:
10天后如果死肥宅的段位达到王者,输出"666";否则输出"777"。
示例1
输入
复制
7 7 7 7 7 7 7 7 7 7
1 1 1 1 1 1 1 1 1 1
输出
复制
777
666
备注:
段位晋级规则为:
黄铜 -> 白银 -> 黄金 -> 白金 -> 钻石 -> 大师 -> 王者
特殊状况:
如果降到黄铜,且下一天仍然没有升段,因为黄铜下面没有其他段位,那么记录信息的队员会在7和0中随机记录一个,7和0都代表当前段位没有发生变化。
如果升到王者,且下一天仍然没有掉段,因为王者之上没有其他段位,那么记录信息的队员会在0和1中随机记录一个,1和0都代表当前段位没有发生变化。

特殊处理一下最大和最小的时候即可

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#define x first
//#define y second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef unsigned long long ULL;

inline int read(int out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 2010 + 10;
const int M = 3e6 + 10;
const int mod = 2333;
const int PP = 13331;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

signed main(){
	int n;
	while(~scanf("%lld", &n)){
		int ans = 3;
		if (n == 1){
			ans += 1;
		}
		else if (n == 7){
			ans -= 1;
		}
		
		for (int i = 1; i <= 9; i ++){
			int x;
			scanf("%lld", &x);
			if (x == 1){
				ans = min(7ll, ans + 1);
			}
			else if (x == 7){
				ans = max(1ll, ans - 1);
			}
		//	cout << ans << endl;
		}
		
		if (ans == 7)   cout << "666" << endl;
		else   cout << "777" << endl;
	}
	return 0;
}

树链博弈
链接:https://ac.nowcoder.com/acm/contest/11517/C
来源:牛客网

题目描述
给定一棵 n 个点的树,其中 1 号结点是根,每个结点要么是黑色要么是白色
现在小 Bo 和小 Biao 要进行博弈,他们两轮流操作,每次选择一个黑色的结点将它变白,之后可以选择任意多个(可以不选)该点的祖先(不包含自己),然后将这些点的颜色翻转,不能进行操作的人输
由于小 Bo 猜拳经常输给小 Biao,他想在这个游戏上扳回一城,现在他想问你给定了一个初始局面,是先手必胜还是后手必胜
输入描述:
第一行一个正整数 n
第二行 n 个整数 w1…wn,wi∈ {0,1},wi=1 表示第 i 个结点一开始是黑点,否则是白点
接下来 n-1 行,每行两个正整数 u,v 表示一条树边 (u,v)
输出描述:
如果先手必胜,输出First ,否则输出Second
示例1
输入
复制
2
1 0
1 2
输出
复制
First
备注:
1≤ n≤ 1000

在这里插入图片描述
如果有一层的黑点数为奇数的话,那么先手最后一个,就可以掌握下一层的局势,就可以从下到上一直掌控局势。因为中间的可以被底下的改变,所以中间的只能让游戏没完没了,所以每个人都从底下向上选,判断每一层的黑点的个数是否是奇数

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#define x first
//#define y second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef unsigned long long ULL;

inline int read(int out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 2010 + 10;
const int M = 3e6 + 10;
const int mod = 2333;
const int PP = 13331;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

int a[N];
int n, m;
int h[N], e[N], w[N], ne[N], idx;
int depth[N];
int cnt[N];

void add(int a, int b){
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void dfs(int u, int father){
	depth[u] = depth[father] + 1;
	if (a[u])    cnt[depth[u]] ++;
	
	for (int i = h[u]; ~i; i = ne[i]){
		int j = e[i];
		if (j == father)  continue;
		dfs(j, u);
	}
}

signed main(){
	scanf("%lld", &n);
	memset(h, -1, sizeof h);
	
	for (int i = 1; i <= n; i ++)   scanf("%lld", &a[i]);
	
	for (int i = 1; i < n; i ++){
		int a, b;
		scanf("%lld%lld", &a, &b);
		add(a, b), add(b, a);	
	}
	
	dfs(1, -1);
	
	bool flag = false;
	for (int i = 1; i <= n; i ++){
		if (cnt[i] & 1){
			cout << "First" << endl;
			flag = true;
			break;
		}	
	}
	
	if (!flag)   cout << "Second" << endl;  
	
	return 0;
}

Rinne Loves Dynamic Graph、
链接:https://ac.nowcoder.com/acm/contest/11517/D
来源:牛客网

题目描述
Rinne 学到了一个新的奇妙的东西叫做动态图,这里的动态图的定义是边权可以随着操作而变动的图。
当我们在这个图上经过一条边的时候,这个图上所有边的边权都会发生变动。
定义变动函数 f(x) = \frac{1}{1-x}f(x)=
1−x
1

,表示我们在图上走过一条边后,图的边权变动情况。
这里指的“图的变动”的意思是将每条边的边权代入上函数,得到的值即为该次变动后的边权。
现在 Rinne 想要知道,在这个变动的图上从 1 到 n 的最短路径。
因为 Rinne 不喜欢负数,所以她只需要你输出经过的边权权值绝对值之和最小的那个值就可以了。
输出答案保留三位小数。
输入描述:
第一行两个正整数 N,M,表示这个动态图的点数和边数。
接下来 M 行,每行三个正整数 u,v,w,表示存在一条连接点 u,v 的无向边,且初始权值为 w。
输出描述:
如果能到达的话,输出边权绝对值之和最小的答案,保留三位小数。
否则请输出 -1。
示例1
输入
复制
3 3
1 2 2
2 3 2
3 1 3
输出
复制
3.000
说明
走 1 \to 2 \to 31→2→3,总花费 2 + |\frac{1}{1-2}| = 32+∣
1−2
1

∣=3
备注:
n \leq 100000,m \leq 300000,2 \leq x \leq 1000n≤100000,m≤300000,2≤x≤1000

分层图的做法,哪些点可以走到哪些点,每个点搞两个虚拟点来存储另外两种状态,跑最短路即可,哪种状态可以到达哪种状态

或者用dp的做法,dist数组存储三维来表示当前对3取余数走了多少步的距离

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#define x first
//#define y second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef unsigned long long ULL;

inline int read(int out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 3e6 + 10;
const int M = 3e6 + 10;
const int mod = 2333;
const int PP = 13331;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

int n, m;

int h[N], e[N], ne[N], idx;
double w[N];
double dist[N];
bool st[N];

void add(int a, int b, double c){
	e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++;
}

void dijkstra(){
	priority_queue<PDI, vector<PDI>, greater<PDI>> heap;
	for (int i = 1; i <= 3 * n; i ++)    dist[i] = 100000000000;
	dist[1] = 0;
	heap.push({0.0, 1});
	
	while(heap.size()){
		auto t = heap.top();
		heap.pop();
		
		int ver = t.second;
		double distance = t.first;
		
		if (st[ver])   continue;
		st[ver] = true;
		
		for (int i = h[ver]; ~i; i = ne[i]){
			int j = e[i];
			
			if (dist[j] > dist[ver] + w[i]){
				dist[j] = dist[ver] + w[i];
				heap.push({dist[j], j});
			}
		}
	}
}

signed main(){
	scanf("%lld%lld", &n, &m);
	memset(h, -1, sizeof h);
	
	for (int i = 1; i <= m; i ++){
		int a, b;
		double c;
		scanf("%lld%lld%lf", &a, &b, &c);
		double w1 = c;
		double w2 = (1.0 / (1 - w1));
		double w3 = (1.0 / (1 - w2));
		
		add(a, b + n, fabs(w1));
		add(b, a + n, fabs(w1));
		add(a + n, b + 2 * n, fabs(w2));
		add(b + n, a + 2 * n, fabs(w2));
		add(a + 2 * n, b, fabs(w3));
		add(b + 2 * n, a, fabs(w3));
	}
	
	dijkstra();
	
	double ans = 100000000000;
	
	for (int i = n; i <= 3 * n; i += n)   ans = min(ans, dist[i]);
	
	if (ans > 10000000000)   cout << "-1" << endl;
	else  printf("%.3lf\n", ans);
	
	return 0;
}

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
#include <ext/rope>
#include <bits/stdc++.h> 

using namespace std;

#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#define x first
//#define y second

int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; 

//typedef __int128 INT;
typedef pair<double, int> PDI;
typedef unsigned long long ULL;

inline int read(int out = 0)
{
    char c;
    while((c=getchar()) < 48 || c > 57);
    while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
    return out; 
}

const int N = 1e5 + 10;
const int M = 6e5 + 10;
const int mod = 1000000007;
const int PP = 13331;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const double PI = acos(-1);

int n, m;
int h[N], e[N], ne[N], idx;
double w[N];
double dist[N][3];
bool st[N][4];

void add(int a, int b, double c){
	e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++;
}

struct Node{
	int flag;
	int x;
	double step;
	bool operator<(const Node &W)const{
		return step > W.step;
	}
};

double get_distance(int flag, double w){
	if (flag % 3 == 0)   return fabs(w);
	else if (flag % 3 == 1)   return (fabs((1.0 / (1 - w))));
	else return fabs(((w - 1.0) / w)); 
}

void dijkstra(){
	for (int i = 1; i <= n; i ++){
		dist[i][0] = 1e12;
		dist[i][1] = 1e12;
		dist[i][2] = 1e12;
	}
	dist[1][0] = 0;
	priority_queue<Node> heap;
	heap.push({0, 1, 0});
	
	while(heap.size()){
		auto t = heap.top();
		heap.pop();
		
		int ver = t.x;
		int flag = t.flag;
		double distance = t.step;
		
		if (st[ver][flag])    continue;
		st[ver][flag] = true;
		
		for (int i = h[ver]; ~i; i = ne[i]){
			int j = e[i];
			int flag1 = (flag + 1) % 3;
			double d = get_distance(flag, w[i]);
			if (dist[j][flag1] > dist[ver][flag] + d){
				dist[j][flag1] = dist[ver][flag] + d;
				heap.push({flag1, j, dist[j][flag1]});
			}
		}
	}
}

signed main(){
	scanf("%lld%lld", &n, &m);
	memset(h, -1, sizeof h);
	
	for (int i = 1; i <= m; i ++){
		int a, b;
		double c;
		scanf("%lld%lld%lf", &a, &b, &c);
		add(a, b, c), add(b, a, c);
	}
	
	dijkstra();
	
	double ans = 1e12;
	
	ans = min(ans, dist[n][0]);
	ans = min(ans, dist[n][1]);
	ans = min(ans, dist[n][2]);
	
	if (ans > 99999999999)   cout << "-1" << endl;
	else   printf("%.3lf\n", ans);   
	
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值