Codeforces Round 890 (Div. 2) D. More Wrong(交互题 贪心/启发式 补写法)

题目

t(t<=100)组样例,长为n(n<=2000)的序列

交互题,每次你可以询问一个区间[l,r]的逆序对数,代价是(r-l)^2

要在5n^2的代价内问出最大元素的位置,输出其位置

思路来源

neal

Codeforces Round 890 (Div. 2) supported by Constructor Institute D (交互+分治) 附加强 - 知乎

题解

赛中开题顺序大失败没看这个sb题

赛后用一种不超过4n^2的搞过去了,也就是分治左右区间,

找到左区间和右区间的极大值的位置,

然后询问两次,决定是左更大还是右更大

看见neal这个最优次数不超过3n^2,补一下

感觉有点哈夫曼树贪心的意思,也有点启发式NTT的合并方式

实际就是当还有x个位置都可以成为答案时,

把他们按位置增序维护在链表里,

每次遍历链表,找到位置最接近的两个数询问

复杂度O(n^2)

构造

根据这个尝试去构造对应的hack方法,

于是,想到的最接近3n方次数的构造方法是

先把n和n-1放两边,n-2放中间,然后递归左右

n=9时,数组形如

9 4 6 3 7 2 5 1 8

证明

 

代码

#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,ll> PI;
#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 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__)
#define ll long long
#define ull unsigned ll
const int N=2e3+10;
int t,n,dp[N][N];
int cal(int l,int r){
	if(l==r)return 0;
    if(~dp[l][r])return dp[l][r];
	printf("? %d %d\n",l,r);
	fflush(stdout);
	int v;
	scanf("%d",&v);
	return dp[l][r]=v;
}
void out(int x){
	printf("! %d\n",x);
	fflush(stdout);
}
int main(){
	sci(t);
	while(t--){
		sci(n);
        vector<int>now(n);
        iota(now.begin(),now.end(),1);
        rep(i,1,n){
            rep(j,i,n){
                dp[i][j]=-1;
            }
        }
        while(SZ(now)>1){
            int dis=n,p=-1,sz=SZ(now)-1;
            rep(i,0,sz-1){
                int w=now[i+1]-now[i];
                if(w<dis)dis=w,p=i;
            }
            int x=cal(now[p],now[p+1]),y=cal(now[p],now[p+1]-1);
            if(x==y)now.erase(now.begin()+p);
            else now.erase(now.begin()+(p+1));
        }
        out(now[0]);
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值