Codeforces Round #737 (Div. 2)
A. Ezzat and Two Subsequences
题意:把两个序列拆分成两个部分,对两个部分做平均值,让两个平均值相加尽可能最大。
题解:可以观察到,将最大的数单独分一个出来,剩下的数一个部分求平均值,然后相加就会最大。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+50;
const int INF = 0x3f3f3f3f;
int main(){
int t;
scanf("%d",&t);
while(t--){
int n;
ll maxs = -INF, sums = 0, x;
scanf("%d",&n);
for(int i = 0;i < n;i++){
scanf("%lld",&x);
sums += x;
maxs = max(maxs,x);
}
// printf("%lld %lld\n",maxs,sums);
printf("%.9lf\n",maxs+(sums-maxs)*1.0/(n-1));
}
return 0;
}
B. Moamen and k-subarrays
题意:将一个序列分成
k
k
k个连续的互不相交的子序列。然后问可不可以通过改变这
k
k
k序列的相对顺序,使得拼完之后的整个序列可以变为从小到大的有序序列。
题解:这个题目只要找先离散化一下,然后在序列里找一下,从小到大,并在离散化后的表中连续的部分有多少个,如果小于等于 k k k则有解,否则无解。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+50;
const int INF = 0x3f3f3f3f;
vector<int> has;
int a[N];
int find(int x){
return lower_bound(has.begin(),has.end(),x)-has.begin();
}
int main(){
int t;
scanf("%d",&t);
while(t--){
has.clear();
int n, k, x = INF;
scanf("%d %d",&n,&k);
for(int i = 0;i < n;i++){
scanf("%d",&a[i]);
has.push_back(a[i]);
}
sort(has.begin(),has.end());
for(int i = 0;i < n;i++){
if(x > a[i] || find(a[i]) - find(x) > 1) k--;
// printf("%d %d %d\n",x,a[i],k);
x = a[i];
}
if(k >= 0) printf("Yes\n");
else printf("No\n");
}
return 0;
}
C. Moamen and XOR
题意:给你一个长度为
n
n
n的序列,序列中每个数的大小范围为
[
0
,
2
k
)
[0,2^k)
[0,2k),然后问你将这个序列所有的数按位与的值会大于按位异或的值的序列有多少个。
题解:观察一下可以发现,这题可以用数位dp来处理,首先无论是 & \& &还是 ⨁ \bigoplus ⨁ 都不会对其他位造成影响,所以可以按位处理。
然后你根据数位dp的处理方式,从高位往低位枚举,如果 n n n为偶数,那么按位处理到第 i i i位时,所有数改位全部取 1 1 1,则 ⨁ \bigoplus ⨁ 的该位值位0, & \& &的该位值为1,所有后面低位的所有的位无论取啥 & \& &的值都会更大,所以算一下 2 k − i 2^{k-i} 2k−i乘一下前面的情况数加上就好了,然后如果 n n n为奇数,则两个都会为 1 1 1,只能枚举到最后一位才能取相等的值最后加一下,然后在注意一下这一位两个都为0的情况,用组合数计算一下即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+50;
const int INF = 0x3f3f3f3f, mod = 1e9 + 7;
vector<int> has;
int a[N];
ll f[N], fact[N], infact[N], sums;
ll qmi(ll x,int k){
ll res = 1;
while(k){
if(k&1) res = (res * x) % mod;
x = (x * x) % mod;
k >>= 1;
}
return res;
}
void getfact(){
fact[0] = infact[0] = 1;
for(int i = 1;i < N;i++){
fact[i] = fact[i-1] * i % mod;
infact[i] = infact[i-1] * qmi(i,mod-2) % mod;
}
}
ll C(int x, int y){
if(x < y) return 0;
else return (fact[x] * infact[y] % mod) * infact[x-y] % mod;
}
void Init(int n, int k){
f[0] = 1;
f[1] = qmi(2,n);
for(int i = 2;i < k;i++) f[i] = (f[i-1]*f[1])%mod;
for(int i = 0;i < n;i+=2){
sums = (C(n,i) + sums) % mod;
// printf("%lld %lld %d %d\n",sums,C(n,i),n,i);
}
}
int main(){
int t;
getfact();
// for(int i = 0;i <= 10;i++) printf("f%lld %lld\n",fact[i],infact[i]); printf("\n");
scanf("%d",&t);
while(t--){
sums = 0;
ll ans = 0, res = 1;
int n, k;
scanf("%d %d",&n,&k);
if(k == 0){
printf("1\n");
continue;
}
Init(n,k);
// printf("sums = %lld\n",sums);
for(int i = k;i > 1;i--){
if((n&1) == 0) ans = (ans + (res*f[i-1]) % mod) % mod;
if(n&1) res = res * (sums + 1) % mod;
else res = res * sums % mod;
// printf("%lld %lld %lld\n",ans,res,f[i-1]);
}
ans = (ans + ((sums+1)*res)%mod) % mod;
printf("%lld\n",ans);
}
return 0;
}
D. Ezzat and Grid
题意:就是给你
n
n
n个从上到下排列的0/1串,初始时全为
0
0
0,然后给你
m
m
m个区间告诉你把第
i
i
i行第
l
l
l列到第
r
r
r列全部附为
1
1
1,最后他要你删掉最少的几行,使得删完之后的行相邻行之间至少某一相同位都有一个
1
1
1。
题解:可以发现这个题可以通过和枚举到某一行,并和他上面的行比较是否有 1 1 1的交集,如果有的话可以连一条有向边,最后只要走一个最长路径就可以了。
但是这个图可能是个完全图,所以直接建边是不可能的,所以我们考虑只建当前和这一行相交的路径最长的那一行的边就可以了,但是逐个比较还是 O ( n m ) O(nm) O(nm)复杂度。然后发现找区间相交的最大值,就是找区间最大值,可以考虑用线段树优化。于是就可以将复杂度优化到 O ( m l o g ( n ) ) O(mlog(n)) O(mlog(n)),然后注意数据范围需要离散化。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int N = 3e5+50;
const int INF = 0x3f3f3f3f, mod = 1e9 + 7;
bool flag[N];
int pre[N];
vector<int> has;
struct Node{
int i, l, r;
friend bool operator <(Node a,Node b){
if(a.i == b.i) return a.l < b.l;
return a.i < b.i;
}
}seg[N];
struct QAQ{
int l, r, maxs, lazy, maxid;
}tree[N*8];
int find(int x){
return lower_bound(has.begin(),has.end(),x) - has.begin();
}
void build(int rt, int l, int r){
tree[rt].l = l; tree[rt].r = r;
tree[rt].lazy = tree[rt].maxs = tree[rt].maxid = 0;
if(l == r) return;
int mid = l+r>>1;
build(rt<<1, l, mid); build(rt<<1|1, mid+1, r);
}
void pushdown(int rt){
if(tree[rt].lazy){
tree[rt<<1].maxs = tree[rt<<1|1].maxs = tree[rt].lazy;
tree[rt<<1].lazy = tree[rt<<1|1].lazy = tree[rt].lazy;
tree[rt<<1].maxid = tree[rt<<1|1].maxid = tree[rt].maxid;
tree[rt].lazy = 0;
}
}
void update(int rt,int l,int r,int x,int id){
if(l <= tree[rt].l && r >= tree[rt].r){
tree[rt].maxs = tree[rt].lazy = x;
tree[rt].maxid = id;
return;
}
pushdown(rt);
int mid = tree[rt].l + tree[rt].r >> 1;
if(mid >= l) update(rt<<1,l,r,x,id);
if(r > mid) update(rt<<1|1,l,r,x,id);
if(tree[rt<<1].maxs > tree[rt<<1|1].maxs){
tree[rt].maxs = tree[rt<<1].maxs;
tree[rt].maxid = tree[rt<<1].maxid;
}
else{
tree[rt].maxs = tree[rt<<1|1].maxs;
tree[rt].maxid = tree[rt<<1|1].maxid;
}
}
P query(int rt,int l,int r){
if(l <= tree[rt].l && r >= tree[rt].r) return P(tree[rt].maxs,tree[rt].maxid);
pushdown(rt);
int mid = tree[rt].l + tree[rt].r >> 1;
P mx = P(0,0);
if(mid >= l) mx = query(rt<<1,l,r);
if(r > mid) mx = max(mx,query(rt<<1|1,l,r));
return mx;
}
int main(){
int n, m;
scanf("%d %d",&n,&m);
has.push_back(0);
for(int i = 0;i < m;i++){
scanf("%d %d %d",&seg[i].i,&seg[i].l,&seg[i].r);
has.push_back(seg[i].l);
has.push_back(seg[i].r);
}
sort(has.begin(), has.end());
has.erase(unique(has.begin(), has.end()), has.end());
int sz = has.size();
sort(seg, seg+m);
build(1,1,sz);
int lz = 0, row = seg[0].i, mx = 0, maxrow = 0;
P temp;
for(int i = 0;i < m;i++){
if(seg[i].i != row){
for(int j = lz;j < i;j++){
update(1,find(seg[j].l),find(seg[j].r),mx+1,row);
}
pre[row] = maxrow;
maxrow = 0;
row = seg[i].i;
lz = i;
mx = 0;
}
temp = query(1,find(seg[i].l),find(seg[i].r));
if(mx < temp.first){
mx = temp.first; maxrow = temp.second;
}
}
for(int i = lz;i < m;i++) update(1,find(seg[i].l),find(seg[i].r),mx+1,row);
pre[row] = maxrow;
temp = query(1,1,sz);
mx = temp.first; maxrow = temp.second;
while(maxrow){
flag[maxrow] = true;
maxrow = pre[maxrow];
}
printf("%d\n",n-mx);
for(int i = 1;i <= n;i++){
if(!flag[i]) printf("%d ",i);
}
return 0;
}