[CF1179E]Alesya and Discrete Mat

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF1179E]Alesya and Discrete Mat相关的知识,希望对你有一定的参考价值。

Alesya and Discrete Mat

题解

首先,我们应该很容易想到一种贪心的思路。
它这个 L n \\fracLn nL相当于恰好将整个 L L L分成 n n n段,显然,对于每一个函数,值域段上的一段肯定就对应定义域上的一段。
我们相当于要将这些段选出来不交,容易发现,是一定存在一种选法的。
我们先将所有函数中第一段右端点最小的函数选出来,此时,其它函数就只用选择第 2 2 2段到第 n n n段了。而且这些函数对应的定义域上区间绝对都是在第一个函数对应区间的右边的,所以我们之后相当于是一个 n − 1 n-1 n1的子问题。
n = 1 n=1 n=1的时候是一定有解的,而其它问题都可以被这样收缩到 n = 1 n=1 n=1,所以也一定有解。

当然,如果直接这样暴力做的话,能过就有鬼了。
我们可以考虑用分治的方法进行优化。
比如说,我们可以将一个 n n n的问题规约成两个 n 2 \\fracn2 2n的问题,这样就会稍微快以点了,但这样也就意味着我们要找的是第 n 2 \\fracn2 2n大的 n 2 \\fracn2 2n位置的分割点。
一种方法是通过二分求出每个 n 2 \\fracn2 2n分割点的位置,再将它们排序。
但是这种方法询问次数是 O ( n log ⁡ 2 n ) O\\left(n\\log^2 n\\right) O(nlog2n),过不了这道题。
没事,我们可以考虑别的方法。
比如说就像 n t h _ e l e m e n t nth\\_element nth_element去找这个点。
每次随机一个点,找到它的分割点位置,与别的点判断,别的分割点是在它的前面还是后面。
判断别的点在它前面还是后面,只需要看这个点在分割点位置是大于 n 2 \\fracn2 2n还是小于 n 2 \\fracn2 2n
如果在它前面的比在它后面的多,说明我们想要的排名 n 2 \\fracn2 2n的点应该是在前面这些点中,往左递归。后面比前面多同理。
这样,每次需要检验的数期望长度是减半的,所以我们这部分的询问次数大概是 O ( T log ⁡ n + n ) O\\left(T\\log n+n\\right) O(Tlogn+n)
容易发现, T T T是随着区间长度逐渐减小的,总共加起来还是 O ( n ) O\\left(n\\right) O(n)的级别吧…
反正这样就可以做到 O ( n log ⁡ n ) O\\left(n\\log n\\right) O(nlogn)了。

源码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> pii;
#define MAXN 2005
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lowbit(x) (x&-x)
const int mo=1e9+7;
const int inv2=5e8+4;
const int jzm=2333;
const int zero=200000;
const int INF=0x3f3f3f3f;
const double eps=1e-12;
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
template<typename _T>
void read(_T &x)
    _T f=1;x=0;char s=getchar();
    while(s<'0'||s>'9')if(s=='-')f=-1;s=getchar();
    while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
    x*=f;

int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int qkpow(int a,int s,int p)int t=1;while(s)if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;return t;
int n,id[MAXN],tl[MAXN],tr[MAXN],td[MAXN],totl,totr,totd;
LL a[MAXN],len,L[MAXN],R[MAXN],las;
mt19937 e(time(0));
uniform_int_distribution<int> gx(0,1000000000);
LL ask(int i,LL x)
    printf("? %d %lld\\n",i,x);fflush(stdout);
    LL res;read(res);return res;

void sakura(int l,int r,LL al,LL ar)
    if(l==r)
        LL t=ask(id[l],las),dl=las,dr=1e18;
        while(dl<dr)
            LL md=dl+dr>>1;
            if(ask(id[l],md)>=t+len/n)dr=md;
            else dl=md+1;
        
        L[id[l]]=las;R[id[l]]=las=dl;
        return ;
    
    int mid=l+r>>1,i=l-1,j=r+1;LL bl=al,br=ar;
    while(i+1<j)
        int x=i+gx(e)%(j-i-1)+1;LL dl=bl,dr=br;totl=totr=totd=0;
        while(dl<dr)LL md=dl+dr>>1;if(ask(id[x],md)>=a[mid])dr=md;else dl=md+1;
        for(int k=i+1;k<j;k++)
            LL tmp=ask(id[k],dl);
            if(tmp>a[mid])tl[++totl]=id[k];
            if(tmp<a[mid])tr[++totr]=id[k];
            if(tmp==a[mid])td[++totd]=id[k];
        
        while(i+totl<mid&&totd)tl[++totl]=td[totd--];
        while(j-totr>mid+1&&totd)tr[++totr]=td[totd--];
        for(int k=1;k<=totl;k++)id[i+k]=tl[k];
        for(int k=1;k<=totr;k++)id[j-k]=tr[k];
        if(i+totl<=mid)i+=totl,bl=dl;
        if(j-totr>mid)j-=totr,br=dr;
    
    sakura(l,mid,al,bl);sakura(mid+1,r,br,ar);

int main()
    read(n);read(len);
    for(int i=1;i<=n;i++)a[i]=len/n*i,id[i]=i;
    las=0;sakura(1,n,0LL,(LL)1e18);puts("!");
    for(int i=1;i<=n;i++)
        printf("%lld %lld\\n",L[i],R[i]);
    fflush(stdout);
    return 0;

谢谢!!!

以上是关于[CF1179E]Alesya and Discrete Mat的主要内容,如果未能解决你的问题,请参考以下文章

(CF#257)B. Jzzhu and Sequences

CF | Alyona and Numbers

Vika and Segments - CF610D

CF 862C Mahmoud and Ehab and the xor(异或)

Kingdom and its Cities - CF613D

CF 979D Kuro and GCD and XOR and SUM(异或 Trie)