2025.5
三山半落青山外,二水中分白鹭洲。
CF1746E1 Joking (Easy Version)
省集讲课过于困难,拼尽全力无法战胜。vp Global Round 不会做 C 题,大战 1h 终于战胜 E1。
一个直接的想法是二分,但是交互库说假话这件事看上去很难判断到底应该在左边还是右边,考虑通过增加询问次数使得在逻辑上判断交互库的真假。同时这个可以回答两次很奇怪,显然可以通过一次回答直接确定一个非 \(x\) 的数,进一步思考利用这个非 \(x\) 的数去限制交互库,但是并没有得到什么有用的做法。貌似不存在什么合理的方法进行二分,索性钦定交互库的真假后进行调整。即设我们的区间分成了 \(a\) 和 \(b\) 两部分,一次询问可以得到在 \(x\) 在哪里,不妨直接认为交互库说了真话,接着二分,但是一直这样下去钦定是很没前途的,我们考虑在接下来的较少数量次二分后判断出来这次二分的真假。经过不断的手玩可以得到做法。由于交互库进行两次回答只有 \(3\) 状态,那么如果区间被分成了四部分,我们总可以删去一部分,这样在一次额外二分后就能确定这次二分的真伪。具体来说就是在假定交互库永远说真话的前提下做两次二分询问,这样总有一个区间无论交互库两句话真假情况如何都一定不会被取到,删去以后重复该过程。即设总的序列为 \(s\),将其分成 \(ab\) 两个区间,将两个区间进一步分为 \(cdef\) 四个区间,询问 \(ab\) 和 \(df\),分类讨论删去哪个。
不难发现最优情况下这样每次会使序列长度变为原来的 \(\frac34\)。考虑边界情况 \(n=3\),我们将 \(1\sim3\) 全问一遍,若问出了 YES 那么利用两次回答的机会可以直接做。否则继续询问一次 \(3\),若两次结果相同就代表全是真话,否则利用回答的机会判断哪句是真话以后再问一次即可(下一次一定是真话)。其余两种边界情况 \(n=1\) 和 \(n=2\) 都是简单的。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define pii std::pair<int,int>
#define vint std::vector<int>
#define vpair std::vector<pii>
#define debug(...) fprintf(stderr,##__VA_ARGS__)
template<typename T>
void read(T &x){
x=0;
int f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
x*=f;
}
std::stack<char>st;
template<typename T>
void print(T x){
if(x==0) putchar('0');
if(x<0) putchar('-'),x=-x;
while(st.size()) st.pop();
while(x) st.push((char)('0'+x%10)),x/=10;
while(st.size()) putchar(st.top()),st.pop();
}
template<typename T>
void printsp(T x){
print(x),putchar(' ');
}
template<typename T>
void println(T x){
print(x),putchar('\n');
}
template<typename T,typename I>
bool chkmin(T &a,I b){
if(a>b) return a=b,1;
return 0;
}
template<typename T,typename I>
bool chkmax(T &a,I b){
if(a<b) return a=b,1;
return 0;
}
template<typename T,typename I>
void addedge(std::vector<I>*vec,T u,T v){
vec[u].push_back(v);
}
template<typename T,typename I,typename K>
void addedge(std::vector<K>*vec,T u,T v,I w){
vec[u].push_back({v,w});
}
template<typename T,typename I>
void addd(std::vector<I>*vec,T u,T v){
addedge(vec,u,v),addedge(vec,v,u);
}
template<typename T,typename I,typename K>
void addd(std::vector<K>*vec,T u,T v,I w){
addedge(vec,u,v,w),addedge(vec,v,u,w);
}
bool Mbe;
const int inf=1e18,MOD1=998244353,MOD2=1e9+7;
const int maxn=1e5+10;
bool vis[maxn];
int cnt,b[maxn],num;
vint vec;
int ask(){
// num++;
// if(num>82) assert(0);
std::cout<<"? "<<vec.size()<<" ";
for(int i:vec) std::cout<<i<<" ";
std::cout<<std::endl;
std::string s;
std::cin>>s;
if(s=="YES") return 1;
return 0;
}
int ans(int x){
num++;
std::cout<<"! "<<x<<std::endl;
std::string s;
std::cin>>s;
if(s==":)") exit(0);
// assert(num!=2);
return 0;
}
bool Men;
signed main(){
debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0);
int n;
std::cin>>n;
while(1){
cnt=0;
for(int i=1;i<=n;i++) if(!vis[i]) b[++cnt]=i;
if(cnt==1){
ans(b[1]);
return 0;
}
if(cnt==3){
vec.clear();
vec.push_back(b[1]);
if(ask()){
ans(b[1]);
vec.clear();
vec.push_back(b[2]);
if(ask()) ans(b[2]);
else ans(b[3]);
return 0;
}else{
vec.clear();
vec.push_back(b[2]);
if(ask()){
ans(b[2]);
ans(b[3]);
}else{
vec.clear();
vec.push_back(b[3]);
if(ask()){
ans(b[3]);
ans(b[1]);
}else{
if(ask()){
ans(b[3]);
vec.clear();
vec.push_back(b[1]);
if(ask()) ans(b[1]);
else ans(b[2]);
// assert(0);
}else{
ans(b[1]),ans(b[2]);
// assert(0);
}
}
}
}
// assert(0);
}
if(cnt==2){
vec.clear();
ans(b[1]);
ans(b[2]);
return 0;
}
int mid=(1+cnt)>>1;
vec.clear();
for(int i=1;i<=mid;i++) vec.push_back(b[i]);
int x=ask();
if(x==0){
int mmid=(mid+1+cnt)>>1;
vec.clear();
for(int i=mmid+1;i<=cnt;i++) vec.push_back(b[i]);
int midd=(1+mid)>>1;
for(int i=midd+1;i<=mid;i++) vec.push_back(b[i]);
int y=ask();
vec.clear();
if(y==0){
for(int i=midd+1;i<=mid;i++) vis[b[i]]=1;
continue;
}else{
for(int i=1;i<=midd;i++) vis[b[i]]=1;
continue;
}
}else{
int mmid=(mid+1+cnt)>>1,midd=(1+mid)>>1;
vec.clear();
for(int i=mmid+1;i<=cnt;i++) vec.push_back(b[i]);
for(int i=midd+1;i<=mid;i++) vec.push_back(b[i]);
int y=ask();
vec.clear();
if(y==0){
for(int i=mmid+1;i<=cnt;i++) vis[b[i]]=1;
continue;
}else{
for(int i=mid+1;i<=mmid;i++) vis[b[i]]=1;
continue;
}
}
}
debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC);
}
QOJ10888 Restore Atlantis
和 uoj 美团杯数据结构那题很像。
首先直接做太困难了。拆贡献到每个点上,这样只需统计每个询问不包含多少个点,考虑求出所有该点出现的地图,设最小的为 \(m_1\),最大的为 \(m_2\),则不出现当且仅当 \(s\le m_1\le m_2\le t\),这显然是一个二维平面上 2side 矩形查询的问题,将横轴翻转一下矩形的样子就比较好看了。考虑如何求出 \(m_1\) 和 \(m_2\),将所有地图从下往上扫,线段树上 set 维护标记永久化,信息是当前区间最小和最大的地图,查询时有一个很好的做法,无需枚举每个位置查询最小值和最大值,由于我们需要线段树上每一个点的信息,直接对线段树 dfs 即可线性处理这一部分。回答询问时按照前面说的得到一个较好的贡献形式后树状数组维护即可。
时间复杂度 \(2\log\),不过由于其中一个是 \(\log 2000\),另一个 \(\log\) 虽然是 set 大一点也无所谓。同时还有一个和 \(4\times 10^6\) 相关的 \(1\log\),这部分由于是树状数组也没啥问题。
点击查看代码
#include<bits/stdc++.h>
//#define int long long
#define fi first
#define se second
#define pii std::pair<int,int>
#define vint std::vector<int>
#define vpair std::vector<pii>
#define debug(...) fprintf(stderr,##__VA_ARGS__)
template<typename T>
void read(T &x){
x=0;
int f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
x*=f;
}
std::stack<char>st;
template<typename T>
void print(T x){
if(x==0) putchar('0');
if(x<0) putchar('-'),x=-x;
while(x) st.push((char)(x%10+'0')),x/=10;
while(st.size()) putchar(st.top()),st.pop();
}
template<typename T>
void printsp(T x){
print(x),putchar(' ');
}
template<typename T>
void println(T x){
print(x),putchar('\n');
}
template<typename T,typename I>
bool chkmax(T &a,I b){
if(a<b) return a=b,1;
return 0;
}
template<typename T,typename I>
bool chkmin(T &a,I b){
if(a>b) return a=b,1;
return 0;
}
bool Mbe;
const int inf=1e9,MOD1=998244353,MOD2=1e9+7;
const int maxn=2000+10,N=1e5+10,lim=1e5;
int n,q,xa[N],xb[N],ya[N],num,yb[N],val[maxn][maxn],qx[N],qy[N],ans[N],tot,col,sum;
vint bg[2010],ed[2010],b[2010],upd[N],qu[N];
struct SegmentTree{
int l[maxn*2],r[maxn*2],ls[maxn*2],rs[maxn*2],tot,mi[maxn*2],mx[maxn*2];
std::set<int>mst[maxn*2];
void clear(){
tot=0;
}
int build(int L,int R){
int p=++tot;
l[p]=L,r[p]=R;
mi[p]=inf,mx[p]=-inf;
mst[p].clear();
if(L==R) return p;
int mid=(L+R)>>1;
ls[p]=build(L,mid),rs[p]=build(mid+1,R);
return p;
}
void add(int p,int L,int R,int k){
if(l[p]>=L&&r[p]<=R){
mst[p].insert(k);
mi[p]=*mst[p].begin();
auto z=mst[p].end();
z--;
mx[p]=*z;
return ;
}
int mid=(l[p]+r[p])>>1;
if(mid>=L) add(ls[p],L,R,k);
if(R>mid) add(rs[p],L,R,k);
}
void erase(int p,int L,int R,int k){
if(l[p]>=L&&r[p]<=R){
mst[p].erase(k);
if(!mst[p].size()) mi[p]=inf,mx[p]=-inf;
else{
mi[p]=*mst[p].begin();
auto z=mst[p].end();
z--;
mx[p]=*z;
}
return ;
}
int mid=(l[p]+r[p])>>1;
if(mid>=L) erase(ls[p],L,R,k);
if(R>mid) erase(rs[p],L,R,k);
return ;
}
pii chk(pii a,pii b){
chkmin(a.fi,b.fi),chkmax(a.se,b.se);
return a;
}
void dfs(int p,pii w){
w=chk(w,{mi[p],mx[p]});
if(l[p]==r[p]){
if(w.fi==inf){
num--;
return ;
}
// if(w.se<=2) debug("%d:(%d,%d)\n",++sum,col,l[p]);
// val[2001-w.fi+1][w.se]++;
upd[lim-w.fi+1].push_back(w.se);
return ;
}
dfs(ls[p],w),dfs(rs[p],w);
}
// pii query(int p,int pos){
// pii res={mi[p],mx[p]};
// if(l[p]==r[p]) return res;
// int mid=(l[p]+r[p])>>1;
// if(mid>=pos) return chk(res,query(ls[p],pos)),res;
// else return chk(res,query(rs[p],pos)),res;
// }
}ds;
// struct BIT{
// const int N=1e5+10;
int ss[N];
void mem(){
// assert(lim<N);
for(int i=0;i<lim;i++) ss[i]=0;//,debug("i=%d N=%d\n",i,N);
// memset(s,s+maxn,0);
}
int lowbit(int x){
return x&(-x);
}
void add(int pos,int k){
for(;pos<=N-10;pos+=lowbit(pos)) ss[pos]+=k;
}
int qry(int pos){
int res=0;
// debug("pos=%d\n",pos);
while(pos) res+=ss[pos],pos-=lowbit(pos),assert(pos>=0);
return res;
}
// }ds_;
bool Men;
signed main(){
debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0);
read(n),read(q);
for(int i=1;i<=n;i++) read(xa[i]),read(ya[i]),read(xb[i]),read(yb[i]),xa[i]++,ya[i]++,bg[ya[i]].push_back(i),ed[yb[i]].push_back(i);
ds.clear();
ds.build(1,2000);
num=2000*2000;
for(int i=1;i<=2000;i++){
for(int j:bg[i]) ds.add(1,xa[j],xb[j],j);
col=i;
ds.dfs(1,{inf,-inf});
for(int j:ed[i]) ds.erase(1,xa[j],xb[j],j);
}
for(int i=1;i<=q;i++){
read(qx[i]),read(qy[i]);
qu[lim+1-qx[i]].push_back(i);
}
// return 0;
// mem();
for(int i=1;i<=lim;i++){
for(int j:upd[i]) add(j,-1);
for(int j:qu[i]) ans[j]=qry(qy[j]);
}
// return 0;
// debug("num=%d %d\n",num,2001*2001);
for(int i=1;i<=q;i++) println(ans[i]+num);
debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC);
}
-
彩灯晚会
-
龙逐千灯幻

浙公网安备 33010602011771号