2020牛客寒假算法基础集训营2

题目链接:

https://ac.nowcoder.com/acm/contest/3003

A题

思路:


求出三种情况的最多获胜局数即可

代码:

#include<bits/stdc++.h>

using namespace std;

int main() {
#ifdef MyTest
	freopen("Sakura.txt", "r", stdin);
#else
	ios::sync_with_stdio(false);
	cin.tie(0);
#endif
	long long a, b, c, x, y, z;
	cin >> a >> b >> c >> x >> y >> z;
	cout << min(a, y) + min(b, z) + min(c, x);
	return 0;
}

B题

思路:


x个1最多组成x个616,y个6最多组成y-1个616;

代码:

#include<bits/stdc++.h>

using namespace std;

int main() {
#ifdef MyTest
	freopen("Sakura.txt", "r", stdin);
#else
	ios::sync_with_stdio(false);
	cin.tie(0);
#endif
	int n;
	string s;
	cin >> n >> s;
	int x = 0, y = 0;
	for(char & c : s) {
		if(c == '1') ++x;
		else if(c == '6') ++y;
	}
	cout << min(y - 1, x);
	return 0;
}

C题

思路:


1.在模 m m m的情况下,一道题做对的概率是 p p p,那么做错的概率是 ( 1 − p ) % m (1-p)\%m (1p)%m ( 1 − p + m ) % m (1-p+m)\%m (1p+m)%m
2.每道题都有做对做错的可能性,设dp[i][j]为前i题做对j题的概率,那么我们很容易可以得到递推式;

代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 2005;
const ll mod = 1e9 + 7;
ll a[maxn][maxn];

int main() {
#ifdef MyTest
	freopen("Sakura.txt", "r", stdin);
#endif
	int n;
	scanf("%d", &n);
	a[0][0] = 1;
	for(int i = 1; i <= n; ++i) {
		ll p;
		scanf("%lld", &p);
		for(int j = 0; j < i; ++j) {
			a[i][j] = (a[i][j] + a[i - 1][j] * (mod + 1 - p)) % mod;
			a[i][j + 1] = (a[i][j + 1] + a[i - 1][j] * p) % mod;
		}
	}
	for(int i = 0; i <= n; i++) {
		printf("%lld ", a[n][i]);	
	}
	return 0;
}

D题

思路:


对于平面上三个点A,B,C:
(1)共线,不可以组成三角形;
(2) ∠ B A C \angle BAC BAC为钝角,即 A B ⃗ ⋅ A C ⃗ < 0 \vec {AB}·\vec {AC}<0 AB AC <0,则可以组成;
(3) ∠ A B C \angle ABC ABC为钝角,即 B A ⃗ ⋅ B C ⃗ < 0 \vec {BA}·\vec {BC}<0 BA BC <0,则可以组成;
(4) ∠ A C B \angle ACB ACB为钝角,即 C A ⃗ ⋅ C B ⃗ < 0 \vec {CA}·\vec {CB}<0 CA CB <0,则可以组成;
(5)其余情况则不可以组成钝角三角形;
我们暴力遍历所有点即可;

代码:

#include<bits/stdc++.h>

using namespace std;

int x[505], y[505];

inline bool check(int & a, int & b, int & c) {
	if((y[c] - y[a]) * (x[b] - x[a]) == (x[c] - x[a]) * (y[b] - y[a])) return false;
	if((x[b] - x[a]) * (x[c] - x[a]) < (y[a] - y[b]) * (y[c] - y[a])) return true;
	if((x[a] - x[b]) * (x[c] - x[b]) < (y[b] - y[a]) * (y[c] - y[b])) return true;
	if((x[b] - x[c]) * (x[a] - x[c]) < (y[c] - y[b]) * (y[a] - y[c])) return true;
	return false;
}

int main() {
#ifdef MyTest
	freopen("Sakura.txt", "r", stdin);
#endif
	int n;
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) scanf("%d %d", x + i, y + i);
	int ans = 0;
	for(int i = 1; i <= n; i++)
	for(int j = i + 1; j <= n; j++)
	for(int k = j + 1; k <= n; k++)
	if(check(i, j, k)) ++ans;
	printf("%d", ans);
	return 0;
}

E题

思路:


1.将等式两边平方我们可以得到 i + j + 2 i j = k i+j+2\sqrt{ij}=k i+j+2ij =k,因此这里要求 i ∗ j i*j ij是一个不大于 n n n的完全平方数;
2.我们遍历所有小于等于 n n n的完全平方数,设 f ( x ) f(x) f(x)为当前遍历到的数 x x x的约数个数,则答案为 ∑ f ( x ) \sum f(x) f(x)

代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

inline ll get(int n) {
	ll ans = 0;
	for(int i = 1; i * i <= n; i++) {
		if(n % i == 0) {
			++ans;
			if(i != n / i) ++ans;	
		}
	}
	return ans;
}

int main() {
#ifdef MyTest
	freopen("Sakura.txt", "r", stdin);
#endif
	ll n, ans = 0;
	cin >> n;
	for(int i = 1; i * i <= n; i++) ans += get(i * i);
	cout << ans;
	return 0;
}

F题

思路:


一个物品,它对自己的加分是x,对对手的加分是y,那么拿走它,相当于让自己得到x分让对手减少y分,那么对整体的贡献就是x+y分;
因此每个人每次都会选取x+y最大的物品;

代码:

#include<bits/stdc++.h>

using namespace std;

const int maxn = 2e5 + 5;
struct goods {
	int id, v;
	bool operator < (const goods & g) const {
		return v > g.v;	
	}
}g[maxn];
int n, a[maxn];

int main() {
#ifdef MyTest
	freopen("Sakura.txt", "r", stdin);
#endif
	scanf("%d", &n);
	for(int i = 0; i < n; i++) scanf("%d", a + i);
	for(int i = 0; i < n; i++) {
		int b;
		scanf("%d", &b);
		g[i].id = i + 1, g[i].v = a[i] + b;
	}
	sort(g, g + n);
	for(int i = 0; i < n; i += 2) printf("%d ", g[i].id);
	putchar('\n');
	for(int i = 1; i < n; i += 2) printf("%d ", g[i].id);
	return 0;
}

G题

思路:


我们的任务就是判断给定的 a , b , c , d , e , f , g a,b,c,d,e,f,g a,b,c,d,e,f,g是否满足 a d + b e + c f = g a^d+b^e+c^f=g ad+be+cf=g这个等式;
1.将左边这个等式的值计算出来是不现实的,因为过程变量可能会非常大;
2.因此我们采用取模的想法,将左式的计算在模 p p p的情况下计算,此时左式的结果运用快速幂可以迅速求得;
3.我们可以多取几个不同的模以提高判断的准确性;

代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
ll a, b, c, d, e, f, g;

ll pow_mod(ll x, ll n, ll mod) {
	ll res = 1;
	while(n) {
		if(n & 1) res = res * x % mod;
		x = x * x % mod;
		n >>= 1;	
	}
	return res;
}
bool check() {
	bool flag = true;
	for(ll m = 1e9 + 1; m <= 1e9 + 10; m++) {
		ll x = pow_mod(a, d, m);
		ll y = pow_mod(b, e, m);
		ll z = pow_mod(c, f, m);
		if(x + y + z != g) flag = false;	
	}
	puts(flag ? "Yes" : "No");
}

int main() {
#ifdef MyTest
	freopen("Sakura.txt", "r", stdin);
#endif
	int kase;
	for(cin >> kase; kase--;) {
		cin >> a >> b >> c>> d >> e >> f >>g;
		check();	
	}
	return 0;
}

H题

思路:


我们需要先对序列进行排序;
由贪心的思想我们知道此时一次施法的元素必定是连续的,我们将这些连续的元素看出一个个线段;
d p [ i ] dp[i] dp[i]表示 n = = i n==i n==i时的答案( i > = k i>=k i>=k)
则对于第 i i i个元素,它有两种选择:
(1)它是一个长度大于k的线段的末尾,它一定接在 i − 1 i-1 i1的后面,即 d p [ i ] = d p [ i − 1 ] + a [ i ] − a [ i − 1 ] dp[i]=dp[i-1]+a[i]-a[i-1] dp[i]=dp[i1]+a[i]a[i1]
(2)它是一个长度等于k的线段的末尾,即从 i − k + 1 i-k+1 ik+1 i i i是连续的一段,那么 d p [ i ] = d p [ i − k ] + a [ i ] − a [ i − k + 1 ] dp[i]=dp[i-k]+a[i]-a[i-k+1] dp[i]=dp[ik]+a[i]a[ik+1]
那么 d p [ i ] dp[i] dp[i]自然是选取这两种情况中的较小值;

代码:

#include<bits/stdc++.h>

using namespace std;

const int maxn = 3e5 + 5;
const long long inf = 1ll << 60;
int n, k;
long long a[maxn], dp[maxn];

int main() {
#ifdef MyTest
	freopen("Sakura.txt", "r", stdin);
#endif
	scanf("%d %d", &n, &k);
	for(int i = 1; i <= n; ++i) scanf("%lld", a + i);
	sort(a + 1, a + n + 1);
	for(int i = 1; i < k; ++i) dp[i] = inf;
	for(int i = k; i <= n; ++i) {
		dp[i] = min(dp[i - 1] + a[i] - a[i - 1], dp[i - k] + a[i] - a[i - k + 1]);	
	}
	printf("%lld", dp[n]);
	return 0;
}

I题

思路:


首先需要去重,因为权值相同的点互相连接代价为0;
设去重后还剩 n n n个;
假设存在 k ( k ≥ 0 ) k(k\geq 0) k(k0),使得二进制的第 k k k位,对于所有的权值,存在第 k k k位为0的值( v i v_i vi)且存在第 k k k位为1的值( v j v_j vj),那么我们需要找到最小的 k k k,此时所有第 k k k位为1的都和 v i v_i vi相连,所有第 k k k位为0的都和 v j v_j vj相连,且每次连接的花费为 2 k 2^k 2k

代码:

#include<bits/stdc++.h>

using namespace std;

#define lowbit(x) ((x) & -(x))
int n, v[200005];

int main() {
#ifdef MyTest
	freopen("Sakura.txt", "r", stdin);
#endif
	scanf("%d", &n);
	for(int i = 0; i < n; i++) scanf("%d", v + i);
	sort(v, v + n);
	int top = unique(v, v + n) - v, x = INT_MAX, y = 0;
	for(int i = 0; i < top; i++) {
		x &= v[i];
		y |= v[i];		
	}
	printf("%lld", (long long)lowbit(x ^ y) * (long long)(top - 1));
	return 0;
}

J题

思路:


待补

代码:


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值