2013多校联合3 1010 No Pain No Game(hdu 4630)

http://acm.hdu.edu.cn/showproblem.php?pid=4630


No Pain No Game

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 72    Accepted Submission(s): 21


Problem Description
Life is a game,and you lose it,so you suicide.
But you can not kill yourself before you solve this problem:
Given you a sequence of number a 1, a 2, ..., a n.They are also a permutation of 1...n.
You need to answer some queries,each with the following format:
If we chose two number a,b (shouldn't be the same) from interval [l, r],what is the maximum gcd(a, b)? If there's no way to choose two distinct number(l=r) then the answer is zero.
 

Input
First line contains a number T(T <= 5),denote the number of test cases.
Then follow T test cases.
For each test cases,the first line contains a number n(1 <= n <= 50000).
The second line contains n number a 1, a 2, ..., a n.
The third line contains a number Q(1 <= Q <= 50000) denoting the number of queries.
Then Q lines follows,each lines contains two integer l, r(1 <= l <= r <= n),denote a query.
 

Output
For each test cases,for each query print the answer in one line.
 


思路:设数列为a[1]~a[n] ,我们·‚从左往右扫描,依次加入a[i],我们设r为当前位置,po[x]为当前位置之前,有因数x的数所出现的位置中,最靠右的那个位置,设dp[i]为位置i到当前为位置r之间(也就是区间[i,r])GCD的最大值,则我们枚举a[i]的所有因数xi,则我们可以将区间[1,po[xi]]中所有小于xi的dp项赋值为xi,这可以用线段树来维护,更新后再将po[xi]=r,那么枚举玩a[i]的所有因数后,我们可以知道对于所有l(l<=r)区间[l,r]中GCD的最大值。所以我们需要一开始将1到50000的所有因数求出来,并且将询问按照R从小到大排序,离线处理即可。以下是代码。

线段树写的很挫,G++还TLE了,C++1700ms卡过。。。仅供参考。。。


#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <vector>
#define maxn 50010
#define mid ((t[p].l+t[p].r)>>1)
#define ls (p<<1)
#define rs (ls|1)
using namespace std;
struct tree
{
    int l,r;
    int lazy;
}t[maxn<<2];
void pushdown(int p)
{
    if(t[p].lazy)
    {
        t[ls].lazy=max(t[ls].lazy,t[p].lazy);
        t[rs].lazy=max(t[rs].lazy,t[p].lazy);
        t[p].lazy=0;
    }
}
void build(int p,int l,int r)
{
    t[p].l=l,t[p].r=r,t[p].lazy=0;
    if(l==r)
    {
        return;
    }
    build(ls,l,mid);
    build(rs,mid+1,r);
}
void change(int p,int l,int r,int val)
{
    if(t[p].l==l&&t[p].r==r)
    {
        t[p].lazy=max(t[p].lazy,val);
        return;
    }
    pushdown(p);
    if(l>mid)
    change(rs,l,r,val);
    else if(r<=mid)
    change(ls,l,r,val);
    else
    {
        change(ls,l,mid,val);
        change(rs,mid+1,r,val);
    }
}
int query(int p,int x)
{
    if(t[p].l==t[p].r)
    return t[p].lazy;
    pushdown(p);
    if(x>mid)
    return query(rs,x);
    else
    return query(ls,x);
}
vector<int> vec[maxn];
void init()
{
    int i;
    for(i=1;i<=50000;i++)
    {
        for(int j=i;j<=50000;j+=i)
        {
            vec[j].push_back(i);
        }
    }
}
int po[maxn],a[maxn],ans[maxn];
struct ask
{
    int num;
    int l,r;
}as[maxn];
bool cmp(ask a,ask b)
{
    return a.r<b.r;
}
int main()
{
 // freopen("dd.txt","r",stdin);
  init();
  int ncase;
  scanf("%d",&ncase);
  while(ncase--)
  {
      int n,i,q;
      scanf("%d",&n);
      build(1,1,n);
      for(i=1;i<=n;i++)
      {
          scanf("%d",&a[i]);
          po[i]=0;
      }
      scanf("%d",&q);
      for(i=1;i<=q;i++)
      {
          scanf("%d%d",&as[i].l,&as[i].r);
          as[i].num=i;
      }
      sort(as+1,as+q+1,cmp);
      int qnum=1;
      as[q+1].r=maxn;
      for(i=1;i<=n;i++)
      {
          for(int j=0;j<vec[a[i]].size();j++)
          {
              int tmp=vec[a[i]][j];
              if(po[tmp])
              {
                  change(1,1,po[tmp],tmp);
              }
              po[tmp]=i;
          }
         while(as[qnum].r<=i)
         {
             ans[as[qnum].num]=query(1,as[qnum].l);
             qnum++;
         }
         if(qnum>q)
         break;
      }
      for(i=1;i<=q;i++)
      {
          printf("%d\n",ans[i]);
      }
  }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值