Codeforces Round #737 (Div. 2) 题解
比赛地址:https://codeforces.com/contest/1557。
只有 ABCD 的题解,E 不会。
A
由样例解释可知最佳方案是最大的一组,其他的一组。
typedef long long ll;
const int N=1e5;
int n,a[N+10];
void mian(){
for(int i=1;i<=n;i++)a[i]=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",a+i);
std::sort(a+1,a+n+1);
double ans=0.0;
for(int i=1;i<=n-1;i++)
ans+=a[i];
ans/=(n-1);
ans+=a[n];
printf("%.9lf\n",ans);
}
B
能分到一段当前仅当排序前和排序后都连续。
于是我们可以求出最少分多少段,然后把它和 \(k\) 比较。
typedef long long ll;
const int N=1e5;
int n,k;
std::pair<int,int> a[N+10];
void mian(){
for(int i=1;i<=n;i++)a[i].first=a[i].second=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&a[i].first),a[i].second=i;
std::sort(a+1,a+n+1);
int ans=0;
for(int i=2;i<=n;i++)
if(a[i].second!=a[i-1].second+1)ans++;
if(ans+1<=k)puts("Yes");
else puts("No");
}
C
约定这里的位是指二进制位,最低位是第 \(0\) 位,最高位是第 \(k-1\) 位。
按位考虑。我们枚举一个 \(0\le i\le k-1\),那么满足要求当且仅当第 \(i+1\sim k-1\) 位相同,第 \(i\) 位与起来是 \(1\),异或起来是 \(0\),第 \(0\sim i-1\) 位随便。当然还有一种情况是所有位都相同。
然后对于第 \(i\) 位上的 \(n\) 个数,我们考虑这样一个表:
\(1\) 的个数的奇偶性 | 是否有 \(0\) | \(\land\) | \(\oplus\) |
---|---|---|---|
奇 | 有 | \(0\) | \(1\) |
奇 | 无 | \(1\) | \(1\) |
偶 | 有 | \(0\) | \(0\) |
偶 | 无 | \(1\) | \(0\) |
- 当 \(n\) 是奇数的时候,我们只能让所有位相同,因为根本无法让某一位上有偶数个 \(1\) 且没有 \(0\),此时根据上表可知,对于每一位,满足要求的方案数是 \(1+\left(\binom n0+\binom n2+\binom n4+\cdots\right)=1+2^{n-1}\),又因为一共有 \(k\) 位,所以最终的答案是 \((1+2^{n-1})^k\)。
- 当 \(n\) 是偶数的时候,
- 若所有位相同,答案是 \(\left(\binom n2+\binom n4+\cdots\right)^k=(2^{n-1}-1)^k\)。
- 枚举一个 \(i\),当第 \(i+1\sim k-1\) 位相同,第 \(i\) 位与起来是 \(1\),异或起来是 \(0\),第 \(0\sim i-1\) 位随便时,对于第 \(i+1\sim k-1\) 位,每一位有 \(\binom n2+\binom n4+\cdots=2^{n-1}-1\) 种可能,第 \(i\) 位只能全是 \(1\),第 \(0\sim i-1\) 位每一位有 \(2^n\) 种可能,一共就有 \((2^{n-1}-1)^{k-i-1}(2^n)^i\) 种可能。
typedef long long ll;
const int P=1e9+7;
inline int qpow(int a,int b,int p){
int res=1;
while(b){if(b&1)res=1LL*res*a%p;a=1LL*a*a%p;b>>=1;}
return res;
}
void mian(){
int n,k;
scanf("%d%d",&n,&k);
int ans=0;
if(n%2==1)
ans=qpow(qpow(2,n-1,P)+1,k,P);
if(n%2==0){
for(int i=0;i<k;i++)
ans+=1LL*(qpow(qpow(2,n-1,P)-1,k-i-1,P))*qpow(qpow(2,n,P),i,P)%P,ans%=P;
ans+=1LL*qpow(qpow(2,n-1,P)-1,k,P);
ans%=P;
}
printf("%d\n",ans);
}
D
dp。设 \(f_{i,j}\) 表示前 \(i\) 行最多能保留几行,且我们考虑了第 \(i\) 行第 \(j\) 列这个格子是 \(1\)。
转移的时候考虑所有值为 \(1\) 的 \((k,j)\),那么:
\[f_{i,j}=\max_{1\le k\le i-1,grid_{k,j}=1}\{f_{k,j}+1\}
\]
这个可以用线段树优化。具体的,对于每个 \(j\),我们要维护 \(f_{k,j}\) 的最大值。
具体细节见代码(非 C++11 党勿入):
using ll=long long;
using pii=std::pair<int,int>;
// 区间覆盖,区间 max,还要维护方案
struct SegTree{
struct Node{
pii mx,ctag;
};
std::vector<Node> t;
SegTree(int n=0){
t.resize(n*4+5,{{0,-1},{0,-1}});
}
std::function<int(int)> ls=[](int x)->int{return x<<1;};
std::function<int(int)> rs=[](int x)->int{return x<<1|1;};
std::function<Node(const Node &,const Node &)> pushUp=[](const Node &L,const Node &R)->Node{
return {std::max(L.mx,R.mx),{0,-1}};
};
std::function<void(Node &,const pii &)> pushC=[](Node &now,const pii &ctag)->void{
now.mx=now.ctag=ctag;
};
std::function<void(int)> pushDown=[this](int i)->void{
if(t[i].ctag!=pii({0,-1})){
pushC(t[ls(i)],t[i].ctag);
pushC(t[rs(i)],t[i].ctag);
t[i].ctag={0,-1};
}
};
std::function<void(int,int,int,int,int,const pii &)> modify=[this](int i,int l,int r,int ql,int qr,const pii &x)->void{
if(ql<=l&&r<=qr)return pushC(t[i],x),void();
int mid=(l+r)>>1;
pushDown(i);
if(ql<=mid)modify(ls(i),l,mid,ql,qr,x);
if(qr>mid) modify(rs(i),mid+1,r,ql,qr,x);
t[i]=pushUp(t[ls(i)],t[rs(i)]);
};
std::function<Node(int,int,int,int,int)> query=[this](int i,int l,int r,int ql,int qr)->Node{
if(ql<=l&&r<=qr)return t[i];
int mid=(l+r)>>1;
pushDown(i);
if(ql>mid) return query(rs(i),mid+1,r,ql,qr);
if(qr<=mid)return query(ls(i),l,mid,ql,qr);
return pushUp(query(ls(i),l,mid,ql,qr),query(rs(i),mid+1,r,ql,qr));
};
};
void mian(){
int n,m;
scanf("%d%d",&n,&m);
std::vector<std::vector<pii>> a(n);
for(int i=0;i<m;i++){
int p,l,r;
scanf("%d%d%d",&p,&l,&r);
p--;
a[p].push_back({l,r});
}
// 把所有线段离散化
std::function<void(void)> init=[&]()->void{
std::vector<int> tmp;
for(auto i:a)
for(auto j:i)
tmp.push_back(j.first),tmp.push_back(j.second);
std::sort(tmp.begin(),tmp.end());
auto it=std::unique(tmp.begin(),tmp.end());
tmp.erase(it,tmp.end());
for(auto &i:a)
for(auto &j:i){
j.first=std::lower_bound(tmp.begin(),tmp.end(),j.first)-tmp.begin()+1;
j.second=std::lower_bound(tmp.begin(),tmp.end(),j.second)-tmp.begin()+1;
}
};
init();
std::vector<pii> f(n);
for(auto &x:f)x.second=-1;
SegTree t(m*2);
for(int i=0;i<n;i++){
for(auto j:a[i]){ // 枚举第 i 行所有的值为 1 的格子
auto x=t.query(1,1,m*2,j.first,j.second); // max_{k=1..i-1,grid[k][j]}=1} f[j]
x.mx.first++;
f[i]=std::max(f[i],x.mx);
}
for(auto j:a[i])
t.modify(1,1,m*2,j.first,j.second,{f[i].first,i}); // 更新 max f[k][j]
}
// 输出方案
int p=0;
for(int i=0;i<n;i++)
if(f[i]>f[p])p=i;
std::set<int> ans;
for(int i=0;i<n;i++)ans.insert(i);
for(;p!=-1;p=f[p].second)ans.erase(p);
printf("%d\n",int(ans.size()));
for(auto i:ans)printf("%d ",i+1);
puts("");
}
E
由于这题的 interactor 很水,所以王后这么走都能过。
好吧现在过不了了。
本文来自博客园,作者:registerGen,转载请注明原文链接:https://www.cnblogs.com/registergen/p/cf_round_737_solution.html