Avito Cool Challenge 2018 F. Tricky Interactor(交互 构造)

题目

长为n(n<=300)的01串,初始情况下总共有t(t<=n)个1

你可以询问若干次,

当你询问的区间为[L,R]时,系统会等概率地从[L,n]和[1,R]里选取一个,

将区间的01翻转,翻转操作是可持久化的,即第i次的翻转会对第i+1次的询问生效

询问总次数要求不超过10000,

你需要在若干次询问后,输出原始的01串

特别地,当01串和询问序列顺序都固定的时候,系统随机的返回值序列也是固定的,

也就是说,不会出现ac代码重交wa了的情况

思路来源

乱搞AC

题解

官方题解比较复杂,这里是强行乱搞搞过去的,倒也没错,只是题解做得更优雅吧

搞过去了之后还看了一篇题解,感觉做法也挺好的

对于n=1的情况,直接输出答案即可

询问次数10000,串长300,所以每个位置可以问大概32次,

对于n>=2的情况,先问32次询问[2,n],这样[L,n]对应[2,n],[1,R]对应[1,n]

也就是[2,n]每次必翻,[1,1]有概率翻有概率不翻

这样翻32次,只取其中的偶数次来看,[2,n]一定不翻,[1,1]有概率翻,

试了16次,至少出现一次翻一次没翻的概率很高,那么

①如果b[1]一开始是1,总的1的个数是t,这16次只会出现t和t-1

②如果b[1]一开始是0,总的1的个数是t,这16次只会出现t和t+1,就求出了b[1]

后面求每位的情况也是类似,具体来说,

计[1,i-1]的1的个数为pre,当前无法确定第i位是什么,但是已知[i,n]的个数为suf

①如果b[i]一开始是1,那么翻之前为pre+suf,翻了[1,i]之后,总的1的个数为i-(pre+1)+suf-1

②如果b[i]一开始是0,那么翻之前为pre+suf,翻了[1,i]之后,总的1的个数为i-pre+suf

也就是询问的两种结果,一种结果一定是t,根据另一种结果是什么,去判断b[i]初始的值是什么

但是,这种情况下,需要保证pre和初始局面情况下前缀的1的个数相等,

所以,如果询问了32次后,[1,i]中1的个数pre和后缀个数suf之和(即a[32])与t的个数不等,

说明前缀被翻了,这个时候应该不断重试两次直至总和为t,

也就是,保证后缀没翻的情况下,前缀再被翻回来

而对于前缀01个数情况相等的情况,不会影响上面的两个式子的值,不会影响第i位初始的答案

插曲

一开始写的是固定下来询问[i,n]的次数,然后只用第偶数次的结果

询问16次wa3,24次wa9,30次wa86,32次超次数上限,

后来改成偶数次数、奇数次数的结果(奇数次数的时候[i,n]一定被翻)一起考虑,

此时,询问30次时,还是wa86

最后,加了一个剪枝,也就是,对于当前[i,n]偶数次的询问,

如果已经问出了两种不同的值就break,然后就ac了

最后,看了下ac链接里各样例的询问次数,

把询问10000次降到了4000次, 真·纯纯期望次数

心得

一开始学弟提了一个询问[1,i]32次的方法,

也是先询问[1,1],[1,2],...,直到[1,n]

但是这个做法有个问题,由于后缀是未求出的,并且有概率翻转

那么,如果询问[1,i]的时候,[i+1,n]中01的个数相同,就无法区别是否翻转,

也就是有了后效性,所以被否掉了,想了一下怎么修

于是,把翻前缀改成翻后缀,也就是把已经求出来的翻了,

这样前缀01个数相等的时候,并不会影响没求的数的正确性,因为没求的数没有翻过

并且能够根据前缀和后缀的1的个数推出,也就有了上面的做法

Another Solution

https://www.cnblogs.com/Kobe303/p/16749590.html

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<ll,int> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define scll(a) scanf("%lld",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
const int N=305,M=33;
int n,t,a[M],b[N];
char ans[N];
int ask(int l,int r){
	printf("? %d %d\n",l,r);
	fflush(stdout);
	int v;
	scanf("%d",&v);
	return v;
}
void out(){
	rep(i,1,n)ans[i]=b[i]+'0';
	ans[n+1]='\0';
	printf("! %s",ans+1);
	fflush(stdout);
}
void sol(){
	sci(n),sci(t);
	int pre=0,suf=t;
	rep(i,1,n-1){
		int mn=n,mx=0,lasj=0;
		rep(j,1,32){
			a[j]=ask(i+1,n);
			if(j%2==0){
				mn=min(mn,a[j]);
				mx=max(mx,a[j]);
				if(mn!=mx){lasj=j;break;}
			}
		}
		int now=a[lasj];
		while(now!=t)now=ask(i+1,n),now=ask(i+1,n);
		int one=i-1-pre+suf-1;// zero=i-1-pre+suf+1;
		if(one==(mn^mx^t))b[i]=1;
		else b[i]=0;
		//printf("mn:%d mx:%d mn^mx^t:%d one:%d zero:%d b:%d\n",mn,mx,mn^mx^t,one,zero,b[i]);
		pre+=b[i];suf-=b[i];
	}
	b[n]=suf;
	out();
}
int main(){
	sol();
	return 0;
}
相关推荐
司军礼1 天前
Unity自动打包——Shell交互
unity·游戏引擎·交互
zls3653652 天前
C# WPF 与 JS 交互可以使用的第三方库
开发语言·javascript·c#·wpf·交互
黑科技编辑器2 天前
SVG理论入门?这篇复旦大学学术论文讲透了!
编辑器·新媒体运营·交互·微信公众平台
小乖兽技术2 天前
C#与C++交互开发系列(十九):跨进程通信之套接字(Sockets)
c++·c#·交互·ipc
残念ing3 天前
【Linux】——操作系统-进程详解
linux·开发语言·交互
Amd7944 天前
Nuxt.js 应用中的 nitro:init 事件钩子详解
自定义·交互·生命周期·nuxt·初始化·钩子·nitro
深度学习渣4 天前
SCSI驱动与 UFS 驱动交互概况
驱动开发·交互
小乖兽技术5 天前
C#与C++交互开发系列(十六):使用多线程
c++·c#·交互
梓贤Vigo5 天前
【Axure原型分享】颜色选择器——填充颜色
交互·产品经理·axure·原型
梓贤Vigo5 天前
【Axure视频教程】中继器控制显示不同内容
交互·产品经理·axure·原型·中继器