CF 1182F Maximum Sine——根号算法

题目:http://codeforces.com/contest/1182/problem/F

注意有绝对值。

那么就是 k*p 对 q 取模,找最接近 \(\frac{q}{2}\) 的结果。

也就是 2*k*p 对 2*q 取模,找最接近 q 的结果。

一个二元组,第一维表示 %2q 后与 q 的距离,第二维表示自己的 编号。

对 n 个二元组排序太花时间。

令 \( g(x) = 2*p*x mod (2*q) \) 

把 n 分块,只排序第一个块里的元素。因为 \( g(x+y) = g(x) + g(y) ( mod (2*q) ) \) ,所以其他块里的大小关系也可以通过第一个块的情况得知。

具体来说,设块大小是 bs ,在第 i 块就是要找与 \( q - 2*p*i*bs \) 最接近的元素。

用 lower_bound 的话,为了方便可以使 a[ tot+1 ] = a[ 1 ] , a[ 0 ] = a[ tot ] 。但是不能 a[ 0 ].first = a[ 1 ].first - 2*p , a[ 0 ].second = a[ 1 ].second - 1 ,因为模 2*q 意义下访问 0 就是要访问 tot 而不是真的 0 位置。

一定要注意相同 fir 只能保留最小的 second ,并且别用 unique 因为该函数不能做到刚才那个要求!!!

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define mkp make_pair
#define fi first
#define se second
#define ll long long
using namespace std;
const int N=4e4+5,INF=1e9+5;
int a,b,p,q,p2,q2,bs,tot;
pair<ll,int> c[N],ans;
int main()
{
  int T;scanf("%d",&T);
  while(T--)
    {
      scanf("%d%d%d%d",&a,&b,&p,&q);
      p2=2*p; q2=2*q; bs=sqrt(b-a+1); tot=0;
      for(int i=0;i<bs;i++)
    c[++tot]=mkp((ll)p2*(a+i)%q2,i);
      sort(c+1,c+tot+1);
      //tot=unique(c+1,c+tot+1)-c-1;
      tot=0;
      for(int i=1;i<=bs;i++)
    if(i==1||c[i].fi!=c[i-1].fi)
      c[++tot]=c[i];

      c[0]=c[tot]; c[tot+1]=c[1];//
      /*c[0]=mkp((c[1].fi+q2-p2)%q2,c[1].se-1);
    c[tot+1]=mkp((c[tot].fi+p2)%q2,c[tot].se+1);*/
      int tp=(ll)p2*bs%q2,pls=0,pl2=a;//=a
      ans=mkp(INF,INF);
      for(int i=0,d;i<bs;i++,pls=((ll)pls+tp)%q2,pl2+=bs)
    {
      d=lower_bound(c+1,c+tot+1,mkp(((ll)q+q2-pls)%q2,0))-c-1;//-1
      ans=min(ans,mkp(abs((c[d].fi+pls)%q2-q),c[d].se+pl2));
      ans=min(ans,mkp(abs((c[d+1].fi+pls)%q2-q),c[d+1].se+pl2));
    }
      for(int i=a+bs*bs;i<=b;i++)//a+
    ans=min(ans,mkp(abs((ll)p2*i%q2-q),i));
      printf("%d\n",ans.se);
    }
  return 0;
}

 

posted on 2019-06-19 11:25  Narh  阅读(394)  评论(0编辑  收藏  举报

导航