Codeforces Round #705 (Div. 2) 部分题解

D. GCD of an Array

单点乘并查询序列\(gcd\)\(n,x<=200000\)


对差不多约\(20000\)个素数每个建棵线段树。动态开点即可。

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;

template <class I>
inline void read(I &z)
{
    z=0;
    char c=getchar();int base=1;
    while (!isdigit(c) && c!='-') c=getchar();
    if (c=='-') c=getchar(),base=-1;
    while (isdigit(c)) z=z*10+c-'0',c=getchar();
    z*=base;
}

const int N=200010,M=7.5e6,p=1e9+7;

int check[N];

void Euler()
{
    for (int i=2;i<=200000;++i)
    {
        if (check[i]) continue;
        check[i]=i;
        if (i>=1000) continue;
        for (int j=i*i;j<=200000;j+=i) if (!check[j]) check[j]=i;
    }
}


struct Segment_Tree
{
    struct node { int lc,rc,w; };

    int point,root[N];
    Segment_Tree(LL _point=1):point(_point) {};

    node a[M];

    int newnode() { return ++point; }

    void pushup(int cur) { a[cur].w=min(a[a[cur].lc].w,a[a[cur].rc].w); }

    void update(int cur,int l,int r,int pos,int x)
    {
        if (l==r) return (void)(a[cur].w+=x);
        int mid=l+r>>1;
        if (pos<=mid)
        {
            if (!a[cur].lc) a[cur].lc=newnode();
            update(a[cur].lc,l,mid,pos,x);
        }
        if (pos>mid)
        {
            if (!a[cur].rc) a[cur].rc=newnode();
            update(a[cur].rc,mid+1,r,pos,x);
        }
        pushup(cur);
    }

    int inquire(int cur) { return a[cur].w; }
};

Segment_Tree T;

LL ans=1,n,q,x,y;

void add(int cur,int x)
{
    while (x!=1)
    {
        int k=check[x],c=0;
        while (check[x]==k) ++c,x/=k;
        
        int last=T.inquire(T.root[k]);
        if (!T.root[k]) T.root[k]=T.newnode();
        T.update(T.root[k],1,n,cur,c);
        int now=T.inquire(T.root[k]);
        for (int i=last+1;i<=now;++i) ans=ans*k%p;
    }
}

int main(int argc, char const *argv[])
{
    read(n),read(q);

    Euler();
    
    for (int i=1;i<=n;++i)
    {
        read(x);
        add(i,x);
    }

    for (int i=1;i<=q;++i)
    {
        read(x),read(y);
        add(x,y);
        printf("%lld\n",ans);
    }
    return 0;
}

E. Enormous XOR

给两个等长的\(0/1\)\(l和r\)\(1e6\))(保证\(r\)没有前导零),问从\(l\)\(r\)的最大子段异或和。


注意到若\(l_1=0\)\(r_1=1\)则取\(011...1\)\(100...0\)可得\(111...1\),之后分奇偶讨论\(r\)。若\(r\)为奇数,则\(r\) \(xor\) \((r-1)=1\)\(r\)为偶数类似。

#include<cstdio>
#include<cctype>
#include<cstring>
#define LL long long
using namespace std;
 
template <class I>
inline void read(I &z)
{
    z=0;
    char c=getchar();int base=1;
    while (!isdigit(c) && c!='-') c=getchar();
    if (c=='-') c=getchar(),base=-1;
    while (isdigit(c)) z=z*10+c-'0',c=getchar();
    z*=base;
}
 
const int N=1000010;
 
char l[N],r[N];
int n,fir=1;
 
int check()
{
    for (int i=n;i;--i) if (l[i]!=r[i]) return 0;
    return 1;
}
 
int main(int argc, char const *argv[])
{
    read(n);
    scanf("%s",l+1),scanf("%s",r+1);
 
    if (l[1]=='0' && r[1]=='1')
    {
        for (int i=1;i<=n;++i) putchar('1');
        return 0;
    }
    
    if (r[n]=='1') return printf("%s",r+1),0;
 
    if (check()) return printf("%s",r+1),0;
 
    for (int i=n;i;--i) if (l[i]=='1') l[i]='0'; else { l[i]='1'; break; }
    if (check()) printf("%s",r+1);
    else r[n]='1',printf("%s",r+1);
 
    return 0;
}
posted @ 2021-03-09 23:23  Harexx  阅读(93)  评论(0)    收藏  举报