BUPT Summer Journey #test7 E

 

 

时间限制 2000 ms   内存限制 65536 KB

题目描述

小弱最近在研究质数,他认为两个数互质是一个好性质。现在hiyot大神为了考考他学习的成果,给了他长度为n的整数序列a1、a2 .. an。同时给了他下面了两种操作:
操作一:"1 l r", 先求出区间[l, r]的所有数的gcd, 再计算[2,m]中有多少个数与gcd互质。
操作二: "2 p x", 把a[p]数值替换为x( 1 <= x <= 1000)
小弱是弱渣,但是如果你做出来了,他会认可你为大神,请你帮他算算。

输入格式

有多组数据。
每组数据以n( 1<=n<=10000), m(2<=m<=1000000), q(1<=q<=10000)开头。接下来一行有n(1 <= ai <= 1000)个数。最后q行每行有三个数,对应于一个操作。

输出格式

对每一个查询输出对应个数(如果区间gcd为1,则输出-1)。

输入样例

5 10 10
2 2 3 3 5
1 1 4
1 3 3
1 5 5
1 1 2
2 3 2
2 4 2
1 1 4
2 3 10
2 4 10
1 3 4

输出样例

-1
6 
7
4
4
3

思路:其实这道题来说的话gcd是容易更新的,难就在处理互质上。有两种处理方式,一种是用容斥原理,另外一种是分区间然后统计。由于时限为2000ms都可以过。

代码:

 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#define maxn 20000
//#define LOCAL
using namespace std;
int n,m,q,result,gcd[4*maxn],ans[maxn],a[maxn];
int prime[]={0,2,3,5,7,11,13,17,19,23,29,31};
vector<int> g[2000];
void Init()
{
    for(int i=2;i<=1000;i++)
    {
        g[i].clear();int temp=i;
        for(int j=1;j<=11;j++)
            if(temp%prime[j]==0)
            {
                while(temp%prime[j]==0)temp/=prime[j];
                g[i].push_back(prime[j]);
            }
        if(temp!=1)g[i].push_back(temp);
    }
}
int solve(int a,int m)
{
    int sz=g[a].size();
    int ret=0;
    if(sz==1) ret=m-m/g[a][0];
    else if(sz==2) ret=m-m/g[a][0]-m/g[a][1]+m/(g[a][0]*g[a][1]);
    else if(sz==3){
        int a1=g[a][0],a2=g[a][1],a3=g[a][2];
        ret=m-m/a1-m/a2-m/a3+m/(a1*a2)+m/(a1*a3)+m/(a2*a3)-m/(a1*a2*a3);
    }
    else if(sz==4){
        int a1=g[a][0],a2=g[a][1],a3=g[a][2],a4=g[a][3];
        ret=m-m/a1-m/a2-m/a3-m/a4+m/(a1*a2)+m/(a1*a3)+m/(a1*a4)+m/(a2*a3)+m/(a2*a4)+m/(a3*a4)-m/(a1*a2*a3)-m/(a1*a2*a4)-m/(a1*a3*a4)-m/(a2*a3*a4)+m/(a1*a2*a3*a4);
    }
    else if(sz==5){
        int a1=g[a][0], a2=g[a][1], a3=g[a][2], a4=g[a][3], a5=g[a][4];
        ret=m-m/a1-m/a2-m/a3-m/a4-m/a5+m/(a1*a2)+m/(a1*a3)+m/(a1*a4)+m/(a1*a5)+m/(a2*a3)+m/(a2*a4)+m/(a2*a5)+m/(a3*a4)+m/(a3*a5)+m/(a4*a5)-m/(a1*a2*a3)-m/(a1*a2*a4)-m/(a1*a2*a5)-m/(a1*a3*a4)-m/(a1*a3*a5)-m/(a1*a4*a5)-m/(a2*a3*a4)-m/(a2*a3*a5)-m/(a2*a4*a5)-m/(a3*a4*a5)+m/(a1*a2*a3*a4)+m/(a1*a2*a3*a5)+m/(a1*a2*a4*a5)+m/(a1*a3*a4*a5)+m/(a2*a3*a4*a5)-m/(a1*a2*a3*a4*a5);
    }
    return ret-1;
}
int Gcd(int a,int b)
{
    if(b==0)return a;
    return Gcd(b,a%b);
}
void build(int l,int r,int Ind)
{
    if(l==r){gcd[Ind]=a[l];return;}
    int mid=(l+r)>>1;
    build(l,mid,Ind<<1);
    build(mid+1,r,(Ind<<1)+1);
    gcd[Ind]=Gcd(gcd[Ind<<1],gcd[(Ind<<1)+1]);
}
void Modify(int a,int l,int r,int Ind,int d)
{
    //printf("Up l=%d r=%d\n",l,r);
    if(l==r&&l==a){gcd[Ind]=d;return;}
    int mid=(l+r)>>1;
    if(a<=mid)Modify(a,l,mid,Ind<<1,d);
    else Modify(a,mid+1,r,(Ind<<1)+1,d);
    gcd[Ind]=Gcd(gcd[Ind<<1],gcd[(Ind<<1)+1]);
    //printf("Down l=%d r=%d gcd[%d]=%d\n",l,r,Ind,gcd[Ind]);
}
void query(int a,int b,int l,int r,int Ind)
{
    //printf("Up a=%d b=%d l=%d r=%d ",a,b,l,r);printf("result=%d\n",result);
    if(a<=l&&r<=b){result=Gcd(result,gcd[Ind]);return;}
    int mid=(l+r)>>1;
    if(a<=mid)query(a,b,l,mid,Ind<<1);
    if(mid<b)query(a,b,mid+1,r,(Ind<<1)+1);
    gcd[Ind]=Gcd(gcd[Ind<<1],gcd[(Ind<<1)+1]);
    //printf("Down a=%d b=%d l=%d r=%d gcd[%d]=%d\n",a,b,l,r,Ind,gcd[Ind]);printf("result=%d\n",result);
}
void Cal()
{
    ans[1]=-1;
    for(int i=2;i<=1000;i++)
    {
        int cnt=0,k=m/i,r=m%i;
        for(int j=1;j<i;j++)if(Gcd(i,j)==1)cnt++;
        ans[i]=cnt*k-1;
        for(int j=1;j<=r;j++)if(Gcd(i,j)==1)ans[i]++;
    }
    /*ans[1]=-1;
    for(int i=2;i<=1000;i++)//可能出现的gcd值
    {
        int cnt=0,pr=m/i,la=m%i;
        for(int j=1;j<i;j++)if(Gcd(i,j)==1)cnt++;
        ans[i]=cnt*pr-1;
        for(int j=1;j<=la;j++)if(Gcd(i,j)==1)ans[i]++;
    }*/
}
int main()
{
    #ifdef LOCAL
    freopen("input.txt","r",stdin);
    #endif // LOCALf
    while(scanf("%d%d%d",&n,&m,&q)==3)
    {
        int kind,l,r,x,v;
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        build(1,n,1);
        Init();
        //for(int i=1;i<=10;i++)printf("gcd[%d]=%d\n",i,gcd[i]);
        //cout<<query(1,2,1,n,1)<<endl;
        //Cal();
        for(int i=1;i<=q;i++)
        {
            scanf("%d",&kind);
            if(kind==1)
            {
                scanf("%d%d",&l,&r);
                result=a[r];query(l,r,1,n,1);
                if(result==1)printf("-1\n");
                else
                {
                    int ret=solve(result,m);
                    printf("%d\n",ret);
                }
            }
            if(kind==2){scanf("%d%d",&x,&v);a[x]=v;Modify(x,1,n,1,v);}
        }
 
    }
    return 0;
}


//

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#define maxn 20000
//#define LOCAL
using namespace std;
int n,m,q,result,gcd[4*maxn],ans[maxn],a[maxn];
int prime[]={0,2,3,5,7,11,13,17,19,23,29,31};
vector<int> g[2000];
template<class T>
inline bool read(T &n)
{
    T x=0,tmp=1;char c=getchar();
    while((c<'0'||c>'9')&&c!='-'&&c!=EOF)c=getchar();
    if(c==EOF)return false;
    if(c=='-')c=getchar(),tmp=-1;
    while(c>='0'&&c<='9')x*=10,x+=(c-'0'),c=getchar();
    n=x*tmp;return true;
}
template<class T>
inline void write(T n)
{
    if(n<0){putchar('-');n=-n;}
    int len=0,data[20];
    while(n){data[len++]=n%10;n/=10;}
    if(!len)data[len++]=0;
    while(len--)putchar(data[len]+'0');
}
void Init()
{
    for(int i=2;i<=1000;i++)
    {
        g[i].clear();int temp=i;
        for(int j=1;j<=11;j++)
            if(temp%prime[j]==0)
            {
                while(temp%prime[j]==0)temp/=prime[j];
                g[i].push_back(prime[j]);
            }
        if(temp!=1)g[i].push_back(temp);
    }
}
int solve(int a,int m)
{
    int sz=g[a].size();
    int ret=0;
    if(sz==1) ret=m-m/g[a][0];
    else if(sz==2) ret=m-m/g[a][0]-m/g[a][1]+m/(g[a][0]*g[a][1]);
    else if(sz==3){
        int a1=g[a][0],a2=g[a][1],a3=g[a][2];
        ret=m-m/a1-m/a2-m/a3+m/(a1*a2)+m/(a1*a3)+m/(a2*a3)-m/(a1*a2*a3);
    }
    else if(sz==4){
        int a1=g[a][0],a2=g[a][1],a3=g[a][2],a4=g[a][3];
        ret=m-m/a1-m/a2-m/a3-m/a4+m/(a1*a2)+m/(a1*a3)+m/(a1*a4)+m/(a2*a3)+m/(a2*a4)+m/(a3*a4)-m/(a1*a2*a3)-m/(a1*a2*a4)-m/(a1*a3*a4)-m/(a2*a3*a4)+m/(a1*a2*a3*a4);
    }
    else if(sz==5){
        int a1=g[a][0], a2=g[a][1], a3=g[a][2], a4=g[a][3], a5=g[a][4];
        ret=m-m/a1-m/a2-m/a3-m/a4-m/a5+m/(a1*a2)+m/(a1*a3)+m/(a1*a4)+m/(a1*a5)+m/(a2*a3)+m/(a2*a4)+m/(a2*a5)+m/(a3*a4)+m/(a3*a5)+m/(a4*a5)-m/(a1*a2*a3)-m/(a1*a2*a4)-m/(a1*a2*a5)-m/(a1*a3*a4)-m/(a1*a3*a5)-m/(a1*a4*a5)-m/(a2*a3*a4)-m/(a2*a3*a5)-m/(a2*a4*a5)-m/(a3*a4*a5)+m/(a1*a2*a3*a4)+m/(a1*a2*a3*a5)+m/(a1*a2*a4*a5)+m/(a1*a3*a4*a5)+m/(a2*a3*a4*a5)-m/(a1*a2*a3*a4*a5);
    }
    return ret-1;
}
int Gcd(int a,int b)
{
    if(b==0)return a;
    return Gcd(b,a%b);
}
void build(int l,int r,int Ind)
{
    if(l==r){gcd[Ind]=a[l];return;}
    int mid=(l+r)>>1;
    build(l,mid,Ind<<1);
    build(mid+1,r,(Ind<<1)+1);
    gcd[Ind]=Gcd(gcd[Ind<<1],gcd[(Ind<<1)+1]);
}
void Modify(int a,int l,int r,int Ind,int d)
{
    //printf("Up l=%d r=%d\n",l,r);
    if(l==r&&l==a){gcd[Ind]=d;return;}
    int mid=(l+r)>>1;
    if(a<=mid)Modify(a,l,mid,Ind<<1,d);
    else Modify(a,mid+1,r,(Ind<<1)+1,d);
    gcd[Ind]=Gcd(gcd[Ind<<1],gcd[(Ind<<1)+1]);
    //printf("Down l=%d r=%d gcd[%d]=%d\n",l,r,Ind,gcd[Ind]);
}
void query(int a,int b,int l,int r,int Ind)
{
    //printf("Up a=%d b=%d l=%d r=%d ",a,b,l,r);printf("result=%d\n",result);
    if(a<=l&&r<=b){result=Gcd(result,gcd[Ind]);return;}
    int mid=(l+r)>>1;
    if(a<=mid)query(a,b,l,mid,Ind<<1);
    if(mid<b)query(a,b,mid+1,r,(Ind<<1)+1);
    gcd[Ind]=Gcd(gcd[Ind<<1],gcd[(Ind<<1)+1]);
    //printf("Down a=%d b=%d l=%d r=%d gcd[%d]=%d\n",a,b,l,r,Ind,gcd[Ind]);printf("result=%d\n",result);
}
void Cal()
{
    ans[1]=-1;
    for(int i=2;i<=1000;i++)
    {
        int cnt=0,k=m/i,r=m%i;
        for(int j=1;j<i;j++)if(Gcd(i,j)==1)cnt++;
        ans[i]=cnt*k-1;
        for(int j=1;j<=r;j++)if(Gcd(i,j)==1)ans[i]++;
    }
    /*ans[1]=-1;
    for(int i=2;i<=1000;i++)//可能出现的gcd值
    {
        int cnt=0,pr=m/i,la=m%i;
        for(int j=1;j<i;j++)if(Gcd(i,j)==1)cnt++;
        ans[i]=cnt*pr-1;
        for(int j=1;j<=la;j++)if(Gcd(i,j)==1)ans[i]++;
    }*/
}
int main()
{
    #ifdef LOCAL
    freopen("input.txt","r",stdin);
    #endif // LOCALf
    while(read(n))
    {
        read(m);read(q);
        int kind,l,r,x,v;
        for(int i=1;i<=n;i++)read(a[i]);
        build(1,n,1);
        Init();
        for(int i=1;i<=q;i++)
        {
            read(kind);
            if(kind==1)
            {
                read(l);read(r);
                result=a[r];query(l,r,1,n,1);
                if(result==1){write(-1);printf("\n");}
                else
                {
                    int ret=solve(result,m);
                    write(ret);printf("\n");
                }
            }
            if(kind==2){read(x);read(v);a[x]=v;Modify(x,1,n,1,v);}
        }
 
    }
    return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值