首页 > 其他分享 >牛客练习赛105

牛客练习赛105

时间:2022-11-09 20:02:04浏览次数:71  
标签:方案 练习赛 int LL 牛客 贝贝 ans 105 mod

切蛋糕的贝贝

题意:

将多边形一个蛋糕切成6份,使得面积之比为1:1:4:5:1:4(顺序可以打乱),只有两种切法,一种是将过外

接圆的多边形的对角线,第二种是从多边形的中心和顶点的连线,先给你一个n边形,问是否可以完成这个目标

思路:

虽然有两种切法,但是实际的没什么太大的差距,可以很容易的看出

1、若n是16的倍数,此时完成这个操作只需要5步
2、若n不是16的倍数,此时是根本无法完成这种操作的

时间复杂度:O(1)

代码:

#include <bits/stdc++.h>
using namespace std;


int main() {
	int n;
	cin >> n;
	
	if(n % 16 == 0) cout << 5 << endl;
	else {
		cout << -1 << endl;
	}

	
	return 0;
} 

抱歉,这没有集美

题意:

将1~n随意排列,每一种排列代表一种方案,当一种方案中存在一个位置满足gcd (i,p[i])则,说明Tenshi成为集

美的概率就不为0,问在给定的n的情况下,有多少中这种方案(答案对1e9 + 7取余)

思路:

满足i和p[i]的值是偶数情况时,i和p[i]的值需要都是偶数,所以在n个数中一共存在n / 2(下取整)个偶数,枚举

所有的方案显然很复杂,所以这里可以采用容斥原理,计算方案中不存在这种条件的方案数,对于所以的方案数哟共有n!种方案,互补方案的特点是:

奇数可以放在奇数位上,偶数必须放在奇数位上(在给定的一个n中,偶数的数量 <= 奇数的数量恒成立)

1、当n是奇数时:对于偶数位上一共 (n + 1) / 2 (向下取整)中选法,奇数位上一共有 n / 2 (向下取整)种

选法,这里注意可以存在奇数放在奇数位上的情况出现,

所以此时的方案数是:(n + 1)/ 2)!* (n / 2) !(除法向下取整)

2、当n时偶数是,同理得到方案数为:(n / 2) ! * (n / 2) ! (除法向下取整)

时间复杂度:O(n)

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int mod = 1e9 + 7;

LL solve(int n) {
	LL ans = 1;
	for (int i = 1; i <= n; i ++ ) {
		ans = (ans * i) % mod;
	} 
	return ans % mod;
}

LL cal(int n) {
	int temp = n / 2;
	LL ans = 1;
	
	for (int i = 1; i <= temp; i ++ ) {
		ans = (ans * i) % mod;
		ans = (ans * i) % mod;
	}
	
	return ans % mod;
}

int main() {
	int n;
	cin >> n;
	
	LL sum = solve(n);
	
	if (n % 2 == 1) n ++ ; 
	
	LL temp = cal(n);
	
//	cout << sum << " " << temp << endl;
	
	cout << (sum - temp + mod) % mod << endl;
	
	return 0;
}

打牌的贝贝

题意:

贝贝和宁宁玩扑克牌,里一共有2 * n张牌,规则是:

问贝贝和宁宁各自获胜的数量

思路:

官方的题解中提到了卡特兰常数(不太了解),不如直接用直白的解释

贝贝要是想赢的话,必须手中有一个张大于宁宁手中所有牌的卡牌,所以此时先给贝贝n - 1张牌,然后在剩余的卡牌

种拿一个最大值,就可以满足贝贝赢(而且这个最大值具有唯一性),所以贝贝赢的方案是:C(n - 1, 2 * n)

总方案数是C(n, 2 * n) ,所以宁宁获胜的方案数目是: C(n, 2 * n) - C(n - 1, 2 * n)

时间复杂度:O(3 * n)

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 2e6 + 5; 
const LL mod = 1e9 + 7;

LL num[N];
LL ans[N];
//快速幂
LL qpow(LL a, LL b) {
	LL res = 1;
	
	while (b) {
		if(b & 1) res = res * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	
	return res;
} 

void init() {
	num[1] = 1;
	for (int i = 2; i <= 2000000; i ++ ) {
		num[i] = (num[i - 1] * i) % mod;
	}
	
	ans[2000000] = qpow(num[2000000], mod - 2) % mod;
	
	for (int i = 2000000; i >= 1; i -- ) {
		ans[i - 1] = ans[i] * i % mod; 
	}
}

LL solve(LL m, LL n) {
	return num[n] * ans[m] % mod * ans[n - m] % mod;
}

int main() {
	int t;
	cin >> t;
		
	//将n的阶乘和x ^ mod - 2(1 <= x <= 2000000)都初始化出来,节省时间 
	init(); 
		
	while (t -- ) {
		int n;		
		scanf("%d", &n);
		
		if(n == 1) {
			cout << "1 1" << endl;
			continue;
		}
		
		printf("%lld %lld\n", solve(n - 1, 2 * n), (solve(n, 2 * n) - solve(n - 1, 2 * n) + mod) % mod);  
//这里不要使用endl会爆时间
	}	
	
	
	
	
	return 0;
}

点分治分点

题意:给定一个n个点,m条边的图,定义一条简单路径上的low值为其路径上的边权的最小值,(简单路径不能包含两

个相同的点),d(u, v) 为从 u 到 v 所有简单路径的最大 low 值,对于给定的s,u从1到n输出d(s, u),若是

不存在则输出-1

思路:

在图论结题方法中一般都是先完成建图,然后再在图上进行操作,但是这个题,可以在建图的过程中解决问题

将所有路径按照权值从大到小排序,然后每次将边加到图中,这样每次选出的权值,对于能达到的点而言,都一样是最

小值中的最大值

时间复杂度:不是很清楚,望有大佬解惑(多谢-

代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 2e6 + 5;
struct node {
	int x, y, w;	
}s[N];

bool vis[N];
vector<int> e[N];
int ans[N];

bool cmp(node a, node b) {
	return a.w > b.w;
}

void dfs(int x, int w) {
	vis[x] = 1;
	ans[x] = w;
	
	for (auto i : e[x]) {
		if(!vis[i]) {
			dfs(i, w);
		}
	}
}

int main() {
	int n, m, st;
	scanf("%d%d%d", &n, &m, &st);
	
	for (int i = 1; i <= n; i ++ ) ans[i] = -1;
	
	for (int i = 1; i <= m; i ++ ) {
		cin >> s[i].x >> s[i].y >> s[i].w;
	}
	
	sort(s + 1, s + 1 + m, cmp);
	
	vis[st] = 1;
	for (int i = 1; i <= m; i ++ ) {
		int xx = s[i].x, yy = s[i].y;
		
		e[xx].push_back(yy);
		if(vis[xx] && !vis[yy]) {
			dfs(yy, s[i].w);
		}
	} 
	
	for (int i = 1; i <= n; i ++ ) {
		printf("%d ", ans[i]);
	} 
	
	return 0;
}

参考:https://www.cnblogs.com/hhzp/p/16864121.html

标签:方案,练习赛,int,LL,牛客,贝贝,ans,105,mod
From: https://www.cnblogs.com/luoyefenglin/p/16874990.html

相关文章