Round #737 Div. 2
A. Ezzat and Two Subsequences
题目大意
给出一个长度为 n n n的序列,将这个序列分成非空的两个子序列,使得这两个子序列的平均值之和最大,求最大的平均值之和。组数 t t t 1 ≤ t ≤ 1 0 3 1≤t≤10^3 1≤t≤103, 2 ≤ n ≤ 105 2≤n≤105 2≤n≤105, − 1 0 9 ≤ a i ≤ 1 0 9 −10^9≤a_i≤10^9 −109≤ai≤109,题目保证 n n n的和不超过 3 ⋅ 1 0 5 3⋅10^5 3⋅105。
思路
先
s
o
r
t
sort
sort一下,保证数组单增,然后计算前缀和。枚举
i
i
i,表示子序列
x
x
x是
1...
i
1...i
1...i,子序列
y
y
y是
i
+
1...
n
i+1...n
i+1...n,利用前缀和
O
(
1
)
O(1)
O(1)地计算子序列
x
x
x,
y
y
y的平均值之和,更新答案。
没论证为什么这个是对的,赛时没
s
o
r
t
sort
sort还
W
A
WA
WA了两发,
s
o
r
t
sort
sort之后就过了。貌似是贪心之类的。
代码
#include <bits/stdc++.h>
using namespace std;
long long n, a[100010], t, sum[100010];
double ans;
int main()
{
scanf("%lld", &t);
while(t--)
{
ans = -19260817192;
scanf("%lld", &n);
for(int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
sort(a+1, a+n+1);
for(int i = 1; i <= n; i++)
sum[i] = sum[i-1] + a[i];
for(int i = 1; i < n; i++)
{
double l, r;
l = (double)sum[i]/i;
r = (double)(sum[n]-sum[i])/(n-i);
if(l+r > ans)
ans = l+r;
}
printf("%.12lf\n", ans);
}
return 0;
}
B. Moamen and k-subarrays
题目大意
有一个长度为 n n n的序列,序列里的元素各不相同。现在要通过如下操作将这个序列排成非降序: 1. 1. 1.将这个序列分成 k k k个非空子串,每一个元素都在一个子串里。 2. 2. 2.将这 k k k个子串的顺序任意地重新排列。 3. 3. 3.将排序后的 k k k个子串合并。问能否通过这样的操作使得序列排成非降序。组数 t t t 1 ≤ t ≤ 1 0 3 1≤t≤10^3 1≤t≤103, 1 ≤ k ≤ n ≤ 1 0 5 1≤k≤n≤10^5 1≤k≤n≤105, 0 ≤ ∣ a i ∣ ≤ 1 0 9 0≤|ai|≤10^9 0≤∣ai∣≤109,题目保证 n n n的和不超过 3 ⋅ 1 0 5 3⋅10^5 3⋅105。
思路
如果可以通过这样的操作使得原序列排成非降序,那么每次选取的子串一定是连续递增的,也就是别的子串里不应该有后一个元素和当前元素之间的元素,否则合并后一定不合法。所以先将所有的元素离散化,然后统计所有的连续递增子串的个数,如果小等 k k k则输出 Y E S YES YES,否则输出 N O NO NO。统计的时候连续递增子串就是后一个元素比前一个元素大 1 1 1 的子串。
代码
#include <bits/stdc++.h>
using namespace std;
int n, t, k, a[100010], b[100010], cnt, now;
int main()
{
scanf("%d", &t);
while(t--)
{
cnt = 0;
now = -1;
scanf("%d %d", &n, &k);
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
b[i] = a[i];
}
sort(b+1, b+n+1);
for(int i = 1; i <= n; i++)
a[i] = lower_bound(b+1, b+n+1, a[i]) - b;
for(int i = 1; i <= n; i++)
{
if(a[i] - now != 1)
cnt++;
now = a[i];
}
if(cnt <= k)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
C. Moamen and XOR
题目大意
一个长度为 n n n的序列,序列里的元素非负且小于 2 k 2^k 2k,求使得 a 1 a_1 a1 & \& & a 2 a_2 a2 & \& & a 3 a_3 a3 & … & \&…\& &…& a n ≥ a 1 ⊕ a 2 ⊕ a 3 ⊕ … ⊕ a n a_n≥a_1\oplus a_2\oplus a_3\oplus…\oplus a_n an≥a1⊕a2⊕a3⊕…⊕an成立的序列的个数。答案对 1 e 9 + 7 1e9+7 1e9+7取模。组数 t t t 1 ≤ t ≤ 5 1≤t≤5 1≤t≤5, 1 ≤ n ≤ 2 ⋅ 1 0 5 1≤n≤2⋅10^5 1≤n≤2⋅105, 0 ≤ k ≤ 2 ⋅ 1 0 5 0≤k≤2⋅10^5 0≤k≤2⋅105。 & \& &:位运算与, ⊕ \oplus ⊕:位运算异或。
思路
由题意(数据范围)知,一定是一位一位拆开来做的。
将
a
i
a_i
ai拆成
k
k
k位,每一位都是
0
0
0或
1
1
1,那么合法的序列就是对于每一位
01
01
01,有
n
n
n次
&
\&
& 操作后的结果
≥
\geq
≥
n
n
n次
⊕
\oplus
⊕ 操作后的结果。
对于每一位,显然
&
\&
& 操作的结果只有全为
1
1
1时才是
1
1
1,而此时
⊕
\oplus
⊕ 操作的结果与
1
1
1的个数有关,所以考虑奇偶。
如果
n
n
n是奇数,那么
n
n
n个数的这一位全为
1
1
1时
&
\&
& 操作结果是
1
1
1,
⊕
\oplus
⊕ 操作结果也是
1
1
1。对于其余
&
\&
& 操作结果是
0
0
0的情况,如果想要满足条件,就只有
⊕
\oplus
⊕ 操作结果也是
0
0
0,而这种情况必须
1
1
1的个数是偶数,那么枚举奇数个
0
0
0的情况,利用组合数(高中排列组合题,全排列消序)算出每种情况的方案数,求和。最终答案就是一位时方案数的
k
k
k次幂。
如果
n
n
n是偶数,那么
n
n
n个数的这一位全为
1
1
1时
&
\&
& 操作结果是
1
1
1,而
⊕
\oplus
⊕ 操作结果是
0
0
0。满足合法条件的情况是第
i
i
i位前结果相等,第
i
i
i位
&
\&
& 操作结果为
1
1
1,
⊕
\oplus
⊕ 操作结果为
0
0
0,之后结果可以任意。
1
1
1的个数是偶数时
⊕
\oplus
⊕ 操作结果是
0
0
0,所以枚举偶数个
0
0
0的情况,利用组合数算出每种情况的方案数,求和。最终答案是方案数的
i
−
1
i-1
i−1次幂乘上
2
n
2^n
2n的
k
−
i
k-i
k−i次幂(要么
0
0
0要么
1
1
1的总排列数)再加上两种操作结果每一位都相同时的答案。
阶乘和阶乘的逆元要预处理出来。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10, mod = 1e9+7;
int t, n, k, ans, sum;
int pro[N], inv[N];
int fpm(ll x, int power)
{
x %= mod;
int a = 1;
for (; power; power >>= 1, x = x*x%mod)
if(power & 1) a = a*x%mod;
return a;
}
void init()
{
pro[0] = 1;
for(int i = 1; i < N; i++)
pro[i] = (ll)pro[i-1]*i%mod;
inv[N-1] = fpm(pro[N-1], mod-2);
for(int i = N-1; i; i--)
inv[i-1] = (ll)inv[i]*i%mod;
}
int C(int n, int m)
{
return (ll)pro[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
init();
scanf("%d", &t);
while(t--)
{
scanf("%d %d", &n, &k);
sum = ans = 0;
if(n % 2 == 1)
{
sum += 1;
for(int i = 1; i <= n; i += 2)
sum = (ll)(sum + (ll)C(n, i))%mod;
ans = fpm(sum, k);
}
else
{
for(int i = 2; i <= n; i += 2)
sum = (ll)(sum + (ll)C(n, i))%mod;
int er = fpm(2, n);
for(int i = 1; i <= k; i++)
ans =(ll)(ans + (ll)fpm(sum, i-1)*fpm(er, k-i)%mod)%mod;
ans = (ll)(ans + (ll)fpm(sum, k))%mod;
}
printf("%d\n", ans);
}
return 0;
}
这场比赛是自打牛客罚坐以来打的最爽的一次了,多少让自己觉得其实也没那么废物。 R a n k Rank Rank 2332 2332 2332,继续努力吧。