Codeforces Round #737 (Div. 2) (A,B,C)


A. Ezzat and Two Subsequences

题目大意:
把n个数分成两组,求两组的平均值之和的最大值

思路:
贪心,把最大的数单独分在一组,保证其值不被取平均值给缩小,其他的数分在另一组
注意保留小数要大于7位
AC代码:

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
const int maxn = 1e6 +3;
int a[maxn];
int main(){
	int T;
	scanf("%d", &T);
	while(T--){
		int n;
		scanf("%d",&n);
		double sum=0;
		int maxx=-1e9;
		for(int i=1;i<=n;++i){
			scanf("%d",&a[i]);
			maxx=max(maxx,a[i]);
			sum+=a[i];
		}
		double ans=0;
		ans=maxx+(sum-maxx)/(double)(n-1);
		printf("%.8lf\n",ans);
	}
	return 0;
}

B. Moamen and k-subarrays

题目大意:
将n个数进行分组(只能和相邻的数在一组)
在不改变每组内的顺序使,改变组的顺序,使n个数变成从小到大
问最少分成几组

思路:
因为不能改变组内顺序,所有组内我们必须要保证是升序的,且其他组不能有在该组区间内的数

也就是说每组内的数在n个数排序后依然是相邻且升序的

所以我们将n个数排序,用他们的排名来代替原数组(类似于离散化)
起初分成n组
如果相邻的两个数排名相邻且升序,即a[ i ]的排名=a[ i + 1 ]的排名-1
则这两个数可以分在一个组内

AC代码:

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
const int maxn = 1e6 +3;
int a[maxn];
struct s_node{
	int x;
	int id;
}s[maxn];
bool cmp(s_node a,s_node b){
	if(a.x==b.x)return a.id<b.id;
	return a.x<b.x;
}
int b[maxn];
int main(){
	int T;
	scanf("%d", &T);
	while(T--){
		int n,k;
		scanf("%d %d",&n,&k);
		int sum=n;
		for(int i=1;i<=n;++i){
			scanf("%d",&a[i]);
			s[i].id=i;
			s[i].x=a[i];
			b[i]=0;
		}
		sort(s+1,s+n+1,cmp);
		for(int i=1;i<=n;++i){
			b[s[i].id]=i;
		}
		for(int i=1;i<n;++i){
			if(b[i]==b[i+1]-1)sum--;
		}
		if(sum<=k)printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

C. Moamen and XOR

题目大意:
构造一种n个数(a[ 1 ] 、a[ 2 ] …a[ n ])且每个数<=2^k(2的k次方)的数组,使得
a1 & a2 & a3 …& an >= a1 ^ a2 ^ a3 …^ an (^是异或)

问能找出多少个

思路:
因为每个数都是 k 位的二进制数,每个数的该位计算后等于结果的该位
所有我们直接从高位往低位考虑即可

举个例子
a1 = 10101011
a2 = 10010100
a3 = 10010101
a4 = 10100101
an = 11010101 (k位)
这样我们可以直接考虑每一列
(数值纯属乱打,只是为了便于理解思路,)

首先我们会发现n为偶数和n为奇数的答案计算方式是不一样的
(排列组合,偶数个1异或为0,奇数个1异或为1)

n为奇数时
不存在 与的和 大于 异或和 ,因为与的特性,只要有一个0,这一位就是0
所以只考虑相等的情况,有两种情况
1.每一位全为1
2.有偶数个1时

C n 0 + C n 2 + . . . . . C n n − 1 C_n^0 +C_n^2 +.....C_n^{n-1} Cn0+Cn2+.....Cnn1
可能有人不会算,或者忘记怎么算了

( 1 + 1 ) n = C n 0 + C n 1 + C n 2 . . . . . + C n n − 1 + C n n ( 1 − 1 ) n = C n 0 − C n 1 − C n 2 . . . . . + C n n − 1 − C n n 两 式 相 加 即 可 求 出 C n 0 + C n 2 + . . . . . C n n − 1 = 2 n − 1 (1 + 1)^n = C_n^0 +C_n^1 +C_n^2.....+C_n^{n-1} +C_n^ {n}\\ (1 - 1)^n = C_n^0 -C_n^1 -C_n^2.....+C_n^{n-1} -C_n^ {n}\\ 两式相加 即可求出 C_n^0 +C_n^2 +.....C_n^{n-1} = 2^{n-1} (1+1)n=Cn0+Cn1+Cn2.....+Cnn1+Cnn(11)n=Cn0Cn1Cn2.....+Cnn1CnnCn0+Cn2+.....Cnn1=2n1
这是1位的情况,总共有k位
所以n为奇数时答案为
( 2 n − 1 + 1 ) k (2^{n-1}+1)^k 2n1+1k

n位偶数时
与的和 大于 异或和 的情况类似于奇数,但是全为1的情况变成等于了
所以每位情况为
C n 0 + C n 2 + . . . . . C n n − 2 = 2 n − 1 − 1 C_n^0 +C_n^2 +.....C_n^{n-2}=2^{n-1} - 1 Cn0+Cn2+.....Cnn2=2n11
(计算方法同上)
大于情况答案也就是
( 2 n − 1 − 1 ) k (2^{n-1}-1)^k 2n11k

等于时,我们枚举每一位,当该位前i - 1位大于,第i位打破大于变成相等(该位为1),后面n-i任意
所以第i位对答案的贡献为
( 2 n − 1 − 1 ) i − 1 ∗ ( 2 n ) k − i (2^{n-1}-1)^{i-1}*(2^{n})^{k-i} 2n11i12nki

所以n为偶数的答案为
( 2 n − 1 − 1 ) k + ∑ i ( 2 n − 1 − 1 ) i − 1 ∗ ( 2 n ) k − i (2^{n-1}-1)^k + \sum_{i} (2^{n-1}-1)^{i-1}*(2^{n})^{k-i} 2n11k+i2n11i12nki

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define ll long long 
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 3;
ll quick_pow(ll a, ll b) {
	ll sum = 1;
	while (b) {
		if (b & 1)sum *= a, sum %= mod;
		a *= a; a %= mod;
		b >>= 1;
	}
	return sum % mod;
}
ll pow2[maxn];
int main() {
	int T;
	scanf("%d", &T);
	pow2[0] = 1;
	for (int i = 1; i <= maxn; ++i) {
		pow2[i] = 2 * pow2[i - 1];
		pow2[i] %= mod;
	}
	while (T--) {
		int n, k;
		scanf("%d %d", &n, &k);
		if (n % 2) {
			printf("%lld\n", quick_pow(pow2[n - 1] + 1, k));
		}
		else {
			ll ans = quick_pow(pow2[n - 1] - 1, k);
			for (int i = 1; i <= k; ++i) {
				ans += (quick_pow(pow2[n - 1] - 1, i - 1) * quick_pow(pow2[n], k - i)) % mod;
			}
			printf("%lld\n", ans % mod);
		}
	}
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值