Codeforces Round #737 div 2
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+.....Cnn−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 = 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.....+Cnn−1+Cnn(1−1)n=Cn0−Cn1−Cn2.....+Cnn−1−Cnn两式相加即可求出Cn0+Cn2+.....Cnn−1=2n−1
这是1位的情况,总共有k位
所以n为奇数时答案为
(
2
n
−
1
+
1
)
k
(2^{n-1}+1)^k
(2n−1+1)k
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+.....Cnn−2=2n−1−1
(计算方法同上)
大于情况答案也就是
(
2
n
−
1
−
1
)
k
(2^{n-1}-1)^k
(2n−1−1)k
等于时,我们枚举每一位,当该位前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}
(2n−1−1)i−1∗(2n)k−i
所以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}
(2n−1−1)k+i∑(2n−1−1)i−1∗(2n)k−i
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;
}