• FR #10题解


    好 蠢 啊

    A.

      标准分治。每次从分治区间中找到最大值的位置m,设f[l,r]为[l,r]的答案,那么f[l,r]=f[l,m-1]+f[m+1,r]+跨过m点的贡献。

         然后枚举小的区间放到大的区间中查就行了。复杂度nlog^2n。

         TM的这5e5你给128M怎么回事。。。开6s又怎么回事。。。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 500050
    #define maxq 10000050
    using namespace std;
    int n,a[maxn],b[maxn],hash[maxn],tot=0,ls[maxq/10+1],rs[maxq/10+1],root,tot_pnt=0,cnt=0,kr=0;
    int p;
    struct seg_tr
    {
        int mx,pos;
        seg_tr (int mx,int pos):mx(mx),pos(pos) {}
        seg_tr () {}
    }s[maxq/10+1];
    struct query
    {
        int pos,lim;
    }q1[maxq>>1],q2[maxq>>1];
    int numq1=0,numq2=0,t[maxn];
    long long ans=0;
    bool cmp(query x,query y)
    {
        return x.pos<y.pos;
    }
    int lowbit(int x) {return (x&(-x));}
    int read()
    {
        char ch;int data=0;
        while (ch<'0' || ch>'9') ch=getchar();
        while (ch>='0' && ch<='9')
        {
            data=data*10+ch-'0';
            ch=getchar();
        }
        return data;
    }
    void addq(int nows,int l,int r,int val)
    {
        if (l-1)
        {
            ++numq1;
            q1[numq1].pos=l-1;
            q1[numq1].lim=lower_bound(hash+1,hash+tot+1,val/a[nows])-hash;
            if (hash[q1[numq1].lim]!=(val/a[nows])) q1[numq1].lim--;
        }
        if (r)
        {
            ++numq2;
            q2[numq2].pos=r;
            q2[numq2].lim=lower_bound(hash+1,hash+tot+1,val/a[nows])-hash;
            if (hash[q2[numq2].lim]!=(val/a[nows])) q2[numq2].lim--;
        }
    }
    seg_tr combine(seg_tr x,seg_tr y)
    {
        if (x.mx>y.mx) return x;
        else return y;
    }
    void build(int &now,int left,int right)
    {
        now=++tot_pnt;
        if (left==right) {s[now]=seg_tr(a[left],left);return;}    
        int mid=(left+right)>>1;
        build(ls[now],left,mid);build(rs[now],mid+1,right);
        s[now]=combine(s[ls[now]],s[rs[now]]);
    }
    seg_tr ask(int now,int left,int right,int l,int r)
    {
        if ((left==l) && (right==r)) return s[now];
        int mid=(left+right)>>1;
        if (r<=mid) return ask(ls[now],left,mid,l,r);
        else if (l>=mid+1) return ask(rs[now],mid+1,right,l,r);
        else return combine(ask(ls[now],left,mid,l,mid),ask(rs[now],mid+1,right,mid+1,r));
    }
    void conc1(int left,int right)
    {
        if (left>right) return;
        int pos=ask(root,1,n,left,right).pos;
        if (pos-left+1<=right-pos+1)
            for (int i=left;i<=pos;i++)
                addq(i,pos,right,a[pos]);
        else
            for (int i=pos;i<=right;i++)
                addq(i,left,pos,a[pos]);
        conc1(left,pos-1);conc1(pos+1,right);
    }
    void add(int pos,int val)
    {
        for (int i=pos;i<=tot;i+=lowbit(i))
            t[i]+=val;
    }
    int ask(int pos)
    {
        int ret=0;
        for (int i=pos;i>=1;i-=lowbit(i))
            ret+=t[i];
        return ret;
    }
    int main()
    {
        n=read();
        for (int i=1;i<=n;i++)
        {
            a[i]=read();b[i]=a[i];if (a[i]==1) cnt++;
            hash[++tot]=a[i];
        }
        sort(hash+1,hash+tot+1);tot=unique(hash+1,hash+tot+1)-hash-1;
        for (int i=1;i<=n;i++) b[i]=lower_bound(hash+1,hash+tot+1,a[i])-hash;
        build(root,1,n);
        conc1(1,n);
        sort(q1+1,q1+numq1+1,cmp);sort(q2+1,q2+numq2+1,cmp);
        p=1;
        for (int i=1;i<=n;i++)
        {
            add(b[i],1);
            while (q1[p].pos==i) 
            {
                ans-=ask(q1[p].lim);
                p++;
            }
        }
        p=1;memset(t,0,sizeof(t));
        for (int i=1;i<=n;i++)
        {
             add(b[i],1);
            while (q2[p].pos==i)
            {
                ans+=ask(q2[p].lim);
                p++;
            }
        }
        printf("%lld
    ",ans-cnt);
        return 0;
    }

    B.

      打表发现,变换2^k次之后数组为b,那么b[i]=a[i]^a[i+2^k(从1..n旋转的意义下)]。

        然后按照二进制按位算就行了。

        考试的时候手推到第四次变换觉得一点规律没有。。然后瞬间觉得这是一个组合问题。。。然后又想到lucas。。。越来越远了。。。

        二进制分组是个很重要的想法。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 100500
    using namespace std;
    long long n,m,a[maxn],b[maxn],tab[70];
    long long read()
    {
        char ch;long long data=0;
        while (ch<'0' || ch>'9') ch=getchar();
        while (ch>='0' && ch<='9')
        {
            data=data*10+ch-'0';
            ch=getchar();
        }
        return data;
    }
    long long trans(long long x)
    {
        if (x<=n) return x;
        return (x-1)%n+1;
    }
    int main()
    {
        n=read();m=read();m--;
        for (long long i=1;i<=n;i++) a[i]=read();
        tab[0]=1;for (long long i=1;i<=63;i++) tab[i]=tab[i-1]<<1;
        long long ret=0;
        while (m)
        {
            if (m&1)
            {
                for (long long i=1;i<=n;i++) b[i]=a[i]^a[trans(i+tab[ret])];
                for (long long i=1;i<=n;i++) a[i]=b[i];
            }
            m>>=1;ret++;
        }
        for (long long i=1;i<=n;i++) printf("%lld ",a[i]);
        printf("
    ");
        return 0;
    }

    C.

      首先得到原式=Σ(i=1..√n)Σ(j=i+1..n/i) [gcd(i,j)=1]。

         然后变成两段区间,直接2^质因子个数 容斥。

         就完了

         就完了

         复杂度√nlogn。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxn 100500
    using namespace std;
    long long n,prime[maxn],tot=0,w[maxn][60],ans=0,mn[maxn],f,kr=0;
    bool vis[maxn];
    void get_table()
    {
        for (long long i=2;i<=maxn-500;i++)
        {
            if (!vis[i]) prime[++tot]=mn[i]=i;
            for (long long j=1;i*prime[j]<=maxn-500;j++)
            {
                vis[i*prime[j]]=true;mn[i*prime[j]]=prime[j];
                if (i%prime[j]) continue;break;
            }
        }
        for (long long i=2;i<=maxn-500;i++)
        {
            long long ret=-1,x=i;
            while (x!=1)
            {
                if (mn[x]!=ret) {ret=mn[x];w[i][0]++;w[i][w[i][0]]=mn[x];}
                x/=mn[x];
            }
        }
    }
    void dfs(long long now,long long top,long long ret,long long val,long long n)
    {
        if (now==w[top][0]+1)
        {
            if (!ret) return;
            if (ret&1) kr+=n/val;else kr-=n/val;
            return;
        }
        dfs(now+1,top,ret,val,n);
        dfs(now+1,top,ret+1,val*w[top][now],n);
    }
    void ask(long long n,long long val) {kr=0;dfs(1,val,0,1,n);}
    int main()
    {
        scanf("%lld",&n);
        get_table();
        long long top=sqrt(n);
        for (long long i=2;i<=top;i++)
        {
            ask(n/i,i);ans+=(n/i)-kr;
            ask(i,i);ans-=i-kr;
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    抽象理解切片递归神经网络(SRNN)的结构
    通俗点讲解 RNN、LSTM、GRU
    2019年最强的自然语言处理模式BERT
    LSTM训练机器理解人类交流的进展
    人工智能自动写作软件基于通用预训练方法MASS
    如何理解模拟计算机“大脑”所形成的神经网络
    人工智能自动写作软件2.0时代
    解开神秘的面纱,人工智能算法到底是什么
    人工智能算法有哪些?启发式算法原理
    浅谈人工智能神经网络与工业自动化
  • 原文地址:https://www.cnblogs.com/ziliuziliu/p/6403413.html
Copyright © 2020-2023  润新知