「杂题乱刷」CF1937C & CF1936A
花花场,被前两题给背刺了。
还是来讲下这题思路吧。
算法一
随机选取两个数,正确的概率约为 \(1\%\)。
期望得分 \(0\)。
算法二
两两之间都选一遍,需要选 \(n \times (n-1) /2\) 次。
然后建一个完全图容易求出每个数的大小。
期望得分 \(0\)。
算法三
正片开始赛时做法,然而因时间所迫来不及继续想了。
首先我们可以用 \(n-1\) 次操作求出 \(0\) 的位置。
然后我们可以用 \(n-2\) 次操作求出最大值。
接下来我们找到所有按位或上 \(n-1\) 为最大值的数字。
然后发现这些数字中的最小值和最大值的位置就是答案。
询问次数视数据毒瘤情况在 \(3n \sim 4n\) 之间。
期望得分 \(60\)。
代码:
点击查看代码
/*
Tips:
你数组开小了吗?
你MLE了吗?
你觉得是贪心,是不是该想想dp?
一个小时没调出来,是不是该考虑换题?
*/
#include<bits/stdc++.h>
using namespace std;
#define map unordered_map
#define forl(i,a,b) for(long long i=a;i<=b;i++)
#define forr(i,a,b) for(register long long i=a;i>=b;i--)
#define forll(i,a,b,c) for(register long long i=a;i<=b;i+=c)
#define forrr(i,a,b,c) for(register long long i=a;i>=b;i-=c)
#define lc(x) x<<1
#define rc(x) x<<1|1
#define mid ((l+r)>>1)
#define cin(x) scanf("%lld",&x)
#define cout(x) printf("%lld",x)
#define lowbit(x) x&-x
#define pb push_back
#define pf push_front
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
//#define endl '\n'
#define QwQ return 0;
#define ll long long
#define lcm(x,y) x/__gcd(x,y)*y
#define Sum(x,y) 1ll*(x+y)*(y-x+1)/2
ll t;
void solve()
{
queue<ll>q;
ll n,find0,findn;
cin>>n;
ll maxn=0;
forl(j,0,n-1)
forl(k,0,n-1)
maxn=max(maxn,(j^k));
forl(i,0,n-1)
{
cout<<"? "<<((i==0)?1:0)<<' '<<((i==0)?1:0)<<' '<<((i==0)?1:0)<<' '<<i<<endl;
char x;
cin>>x;
if(x=='=')
{
find0=i;
break;
}
}
ll needfind=(maxn^(n-1)),L=0;
if(needfind==0)
{
cout<<"! "<<find0<<' '<<findn<<endl;
return ;
}
forl(i,0,n-1)
if(i!=find0)
{
L=i;
break;
}
forl(i,0,n-1)
{
if(i==L || i==find0)
continue;
cout<<"? "<<find0<<' '<<i<<' '<<find0<<' '<<L<<endl;
char c;
cin>>c;
if(c=='>')
L=i;
}
findn=L;
forl(i,0,n-1)
if(i!=find0 && i!=findn)
{
L=i;
break;
}
forl(i,0,n-1)
{
if(i==find0 || i==findn || i==L)
continue;
cout<<"? "<<findn<<' '<<i<<' '<<findn<<' '<<L<<endl;
char jy;
cin>>jy;
if(jy=='>')
{
L=i;
q.push(i);
}
else if(jy=='=')
{
q.push(i);
}
else
{
while(!q.empty())
q.pop();
}
}
L=q.front();
q.pop();
if(!q.empty())
{
ll x=q.front();
cout<<"? "<<L<<' '<<find0<<' '<<x<<' '<<find0<<endl;
char st;
cin>>st;
if(st=='>')
L=x;
}
cout<<"! "<<findn<<' '<<L<<endl;
return ;
}
int main()
{
// IOS;
t=1;
cin>>t;
while(t--)
solve();
/******************/
/*while(L<q[i].l) */
/* del(a[L++]);*/
/*while(L>q[i].l) */
/* add(a[--L]);*/
/*while(R<q[i].r) */
/* add(a[++R]);*/
/*while(R>q[i].r) */
/* del(a[R--]);*/
/******************/
QwQ;
}
算法四
优化算法三。
发现可以不求最小值。
然后做完了 /kx /kx /kx
期望得分 \(100\)。
容易证明询问次数在 \(2n \sim 3n\) 之间。
代码:
点击查看代码
/*
Tips:
你数组开小了吗?
你MLE了吗?
你觉得是贪心,是不是该想想dp?
一个小时没调出来,是不是该考虑换题?
*/
#include<bits/stdc++.h>
using namespace std;
#define map unordered_map
#define forl(i,a,b) for(register long long i=a;i<=b;i++)
#define forr(i,a,b) for(register long long i=a;i>=b;i--)
#define forll(i,a,b,c) for(register long long i=a;i<=b;i+=c)
#define forrr(i,a,b,c) for(register long long i=a;i>=b;i-=c)
#define lc(x) x<<1
#define rc(x) x<<1|1
#define mid ((l+r)>>1)
#define cin(x) scanf("%lld",&x)
#define cout(x) printf("%lld",x)
#define lowbit(x) x&-x
#define pb push_back
#define pf push_front
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
//#define endl '\n'
#define QwQ return 0;
#define ll long long
#define lcm(x,y) x/__gcd(x,y)*y
#define Sum(x,y) 1ll*(x+y)*(y-x+1)/2
ll t;
char ask(ll a,ll b,ll c,ll d)
{
cout<<"? "<<a<<' '<<b<<' '<<c<<' '<<d<<endl;
char x;
cin>>x;
return x;
}
void solve()
{
ll n;
cin>>n;
ll L=0,ans,findn=0;
queue<ll>q;
forl(i,1,n-1)
{
char x=ask(i,i,L,L);
if(x=='>')
L=i;
}
q.push(0);
forl(i,1,n-1)
{
char x=ask(findn,L,i,L);
if(x=='<')
{
findn=i;
while(!q.empty())
q.pop();
q.push(i);
}
else if(x=='=')
q.push(i);
}
ans=q.front();
q.pop();
while(!q.empty())
{
ll num=q.front();
char x=ask(ans,ans,num,num);
if(x=='>')
ans=num;
}
cout<<"! "<<L<<' '<<ans<<endl;
}
int main()
{
// IOS;
t=1;
cin>>t;
while(t--)
solve();
/******************/
/*while(L<q[i].l) */
/* del(a[L++]);*/
/*while(L>q[i].l) */
/* add(a[--L]);*/
/*while(R<q[i].r) */
/* add(a[++R]);*/
/*while(R>q[i].r) */
/* del(a[R--]);*/
/******************/
QwQ;
}
总结
此题是一道不错的小清新构造题。