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;
}