赞
踩
t(t<=100)组样例,长为n(n<=2000)的序列
交互题,每次你可以询问一个区间[l,r]的逆序对数,代价是
要在的代价内问出最大元素的位置,输出其位置
neal
赛中开题顺序大失败没看这个sb题
赛后用一种不超过的搞过去了,也就是分治左右区间,
找到左区间和右区间的极大值的位置,
然后询问两次,决定是左更大还是右更大
看见neal这个最优次数不超过,补一下
感觉有点哈夫曼树贪心的意思,也有点启发式NTT的合并方式
实际就是当还有x个位置都可以成为答案时,
把他们按位置增序维护在链表里,
每次遍历链表,找到位置最接近的两个数询问
复杂度
根据这个尝试去构造对应的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;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。