CR655 题解

A. Omkar and Completion

直接输出 \(n\) 个一样的数即可。

B. Omkar and Last Class of Math

找最大的因数即可。我们也可以转化为找最小的因数。注意若原数为质数则令 \(a=1\)

C. Omkar and Baseball

诈骗题。若全部就位则输出 \(0\),若错位的连续则输出 \(1\),否则一次将其全部错位再用一次恢复。

D. Omkar and Circle

我们考虑最终删去了哪些数。如果存在两数连续,那么它们就一定还带了一个数,严格劣于选择两边的数。

故问题转化为找 \([\frac{n}{2}]\) 个不相邻的数最小。

E. Omkar and Last Floor

区间 \(\text{dp}\) 的难点在于想到它。

考虑区间 \(\text{dp}\),考虑一种策略,由于函数是凸的,我们一定希望区间中的一列尽可能地大。

于是有转移 \(dp_{l,r}=\max\limits_{k\in [l,r]} dp_{l,k-1}+dp_{k+1,r}+(\text{区间内且包含 k})^2\)

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
const int N=105;
int n,m,dp[N][N],lft[N][N],rht[N][N];
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		int k=read();
		for(int j=1;j<=k;j++){
			int l=read(),r=read();
			for(int p=l;p<=r;p++)
				lft[i][p]=l,rht[i][p]=r;
		}
	}
	for(int len=1;len<=m;len++)
		for(int l=1;l+len-1<=m;l++){
			int r=l+len-1;
			for(int k=l;k<=r;k++){
				int cnt=0;
				for(int i=1;i<=n;i++)
					if(lft[i][k]>=l&&rht[i][k]<=r)cnt++;
				dp[l][r]=max(dp[l][r],cnt*cnt+dp[l][k-1]+dp[k+1][r]);
			}
		}
	printf("%d\n",dp[1][m]);
	return 0;
}

F. Omkar and Modes

吐槽一句,这个不降的条件在翻译里属实是有些隐蔽。

考虑分治地处理,用 \(solve(l,r)\) 求出区间 \([l,r]\) 内的所有数值。

求一遍区间众数 \(x\) 和出现次数 \(y\)。若我们已经知道一个位置 \(a_p=x\) ,则我们可以使用两次询问求出这个区间。

具体地,我们知道 \([p-y+1,p]\)\([p,p+y-1]\) 之间一定至少有一个的众数也为 \(x\)

如果我们还不知道,那么隔 \(y\) 询问一个单点,注意到我们询问的每一个数都不同,且一定可以询问到一个 \(x\)

但是这样还是会有很多重复的询问浪费了,于是我们利用以前的信息,从之前的最后一个比 \(x\) 小的数的位置开始。

这样的话,询问区间众数一个 \(k\),询问每个单点一个 \(k\),确定区间两个 \(k\),正好 \(4k\),做完了。

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
int n,m,a[maxn];
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
map<int,int>mp;
map<int,int>::iterator it;
inline pii ask(int l,int r){
	if(l<1)l=1;if(r>n)r=n;
	if(l>r)return mkp(0,0);
	printf("? %d %d\n",l,r);
	fflush(stdout);
	int x=read(),y=read();
	return mkp(x,y);
}
inline void solve(int l,int r){
	if(l>r)return;
	//printf("solving interval:[%d,%d]\n",l,r);
	pii now=ask(l,r);
	int x=now.fi,y=now.se;
	if(r-l+1==y){
		for(int i=l;i<=r;i++)a[i]=x;
		mp[x]=l;return;
	}
	if(!mp[x]){
		it=mp.lower_bound(x);--it;
		for(int i=max(l,it->se+y);;i+=y){
			pii cur=ask(i,i);
			mp[cur.fi]=i;
			if(cur.fi==x)break;
		}
	}int pos=mp[x];
	pii L=ask(pos-y+1,pos);
	pii R=ask(pos,pos+y-1);
	int lb=0,rb=0;
	if(L.fi==x)lb=1+pos-L.se,rb=lb+y-1;
	else lb=pos+R.se-y,rb=lb+y-1;
	for(int i=lb;i<=rb;i++)a[i]=x;
	solve(l,lb-1);solve(rb+1,r);
}
int main(){
	mp[0]=0;
	n=read();solve(1,n);
	printf("! ");
	for(int i=1;i<=n;i++)
		printf("%d ",a[i]);puts("");
	fflush(stdout);
    return 0;
}
posted @ 2022-01-23 17:11  syzf2222  阅读(39)  评论(0编辑  收藏  举报