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\)
  1. \(n\) 是奇数的时候,我们只能让所有位相同,因为根本无法让某一位上有偶数个 \(1\) 且没有 \(0\),此时根据上表可知,对于每一位,满足要求的方案数是 \(1+\left(\binom n0+\binom n2+\binom n4+\cdots\right)=1+2^{n-1}\),又因为一共有 \(k\) 位,所以最终的答案是 \((1+2^{n-1})^k\)
  2. \(n\) 是偶数的时候,
    1. 若所有位相同,答案是 \(\left(\binom n2+\binom n4+\cdots\right)^k=(2^{n-1}-1)^k\)
    2. 枚举一个 \(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 很水,所以王后这么走都能过。

好吧现在过不了了。

posted @ 2021-08-10 14:35  registerGen  阅读(139)  评论(0编辑  收藏  举报