zoukankan      html  css  js  c++  java
  • Manthan, Codefest 16 H. Fibonacci-ish II 大力出奇迹 莫队 线段树 矩阵

    H. Fibonacci-ish II

    题目连接:

    http://codeforces.com/contest/633/problem/H

    Description

    Yash is finally tired of computing the length of the longest Fibonacci-ish sequence. He now plays around with more complex things such as Fibonacci-ish potentials.

    Fibonacci-ish potential of an array ai is computed as follows:

    Remove all elements j if there exists i < j such that ai = aj.
    Sort the remaining elements in ascending order, i.e. a1 < a2 < ... < an.
    Compute the potential as P(a) = a1·F1 + a2·F2 + ... + an·Fn, where Fi is the i-th Fibonacci number (see notes for clarification).
    You are given an array ai of length n and q ranges from lj to rj. For each range j you have to compute the Fibonacci-ish potential of the array bi, composed using all elements of ai from lj to rj inclusive. Find these potentials modulo m.

    Input

    The first line of the input contains integers of n and m (1 ≤ n, m ≤ 30 000) — the length of the initial array and the modulo, respectively.

    The next line contains n integers ai (0 ≤ ai ≤ 109) — elements of the array.

    Then follow the number of ranges q (1 ≤ q ≤ 30 000).

    Last q lines contain pairs of indices li and ri (1 ≤ li ≤ ri ≤ n) — ranges to compute Fibonacci-ish potentials.

    Output

    Print q lines, i-th of them must contain the Fibonacci-ish potential of the i-th range modulo m.

    Sample Input

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

    Sample Output

    3
    3

    Hint

    题意

    给你n个数,然后有q次询问

    每次询问给你l,r区间

    你首先得把l,r区间的数全部拿出来,从小到大排序,然后再去重

    然后答案就等于ans = f[1]*a[1]+f[2]*a[2]....+f[n]*a[n]

    其中f[i]是第i个fib数

    要求答案mod m

    题解:

    现在出题人总喜欢艹一些大新闻出来

    出一些复杂度迷的题目

    这道题正解是莫队+奇怪的东西去维护

    但是由于常数太大了,还没有大力出奇迹的暴力跑得快……

    你说肿么办?

    正解如下:

    莫队去处理询问,然后线段树去处理答案

    线段树怎么处理呢?

    这里比较麻烦处理的是push_up

    push_up你可以用矩阵去写。

    每个点维护两个矩阵,[1][2]是答案的矩阵,[2][2]是fib的矩阵

    a[i][1][2] = a[i*2][1][2] + a[i*2+1][1][2] * a[i*2][2][2]

    a[i][2][2] = a[i*2][2][2]*a[i*2+1][2][2]

    乘号是矩阵乘法

    当然,用数学方法也可以

    f(k+1)*(a1*f(i)+a2*f(i+1)+...)+f(k)*(a1*(f(i-1))+a2*f(i)....) = a1*f(i+k)+a2*f(i+k+1).....

    大暴力代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 3e4+5;
    pair<int,int> a[maxn];
    int ans[maxn],step[maxn],f[maxn],l[maxn],r[maxn],last[maxn];
    
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i].first),a[i].second=i;
        sort(a+1,a+1+n);
        f[0]=1,f[1]=1;
        for(int i=2;i<=n;i++)
            f[i]=(f[i-1]+f[i-2])%m;
        int q;scanf("%d",&q);
        for(int i=1;i<=q;i++)
        {
            scanf("%d%d",&l[i],&r[i]);
            last[i]=-1;
        }
        for(int i=1;i<=n;i++)
        {
            int d = a[i].first % m;
            for(int j=1;j<=q;j++)
            {
                if(a[i].second<l[j]||a[i].second>r[j])continue;
                if(a[i].first==last[j])continue;
                ans[j]=(ans[j]+f[step[j]++]*d)%m;
                last[j]=a[i].first;
            }
        }
        for(int i=1;i<=q;i++)
            printf("%d
    ",ans[i]);
    }
    

    莫队

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 3e4+5;
    int a[maxn],pos[maxn],q,n,m,d[maxn];
    int fib[maxn][2];
    map<int,int> H;
    vector<int> V;
    long long Ans[maxn];
    int cnt[maxn];
    typedef int SgTreeDataType;
    struct treenode
    {
        int L , R  ;
        SgTreeDataType sum1,sum2,siz;
        void update(SgTreeDataType v)
        {
            siz = v;
            sum1 = sum2 = v*d[L]%m;
        }
    };
    
    treenode tree[maxn*4];
    
    inline void push_down(int o)
    {
    
    }
    
    inline void push_up(int o)
    {
        tree[o].siz = tree[2*o].siz + tree[2*o+1].siz;
        tree[o].sum1 = (tree[2*o].sum1+fib[tree[2*o].siz][0]*tree[o*2+1].sum1+fib[tree[2*o].siz][1]*tree[o*2+1].sum2)%m;
        tree[o].sum2 = (tree[2*o].sum2+fib[tree[2*o].siz+1][0]*tree[o*2+1].sum1+fib[tree[2*o].siz+1][1]*tree[o*2+1].sum2)%m;
    }
    
    inline void build_tree(int L , int R , int o)
    {
        tree[o].L = L , tree[o].R = R,tree[o].sum1 = tree[o].sum2 = tree[o].siz = 0;
        if (R > L)
        {
            int mid = (L+R) >> 1;
            build_tree(L,mid,o*2);
            build_tree(mid+1,R,o*2+1);
        }
    }
    
    inline void update(int QL,int QR,SgTreeDataType v,int o)
    {
        int L = tree[o].L , R = tree[o].R;
        if (QL <= L && R <= QR) tree[o].update(v);
        else
        {
            push_down(o);
            int mid = (L+R)>>1;
            if (QL <= mid) update(QL,QR,v,o*2);
            if (QR >  mid) update(QL,QR,v,o*2+1);
            push_up(o);
        }
    }
    struct query
    {
        int l,r,id;
    }Q[maxn];
    bool cmp(query a,query b)
    {
        if(pos[a.l]==pos[b.l])
            return a.r<b.r;
        return pos[a.l]<pos[b.l];
    }
    void Updata(int x)
    {
        int p = H[a[x]];
        cnt[p]++;
        if(cnt[p]==1)
            update(p,p,1,1);
    }
    void Delete(int x)
    {
        int p = H[a[x]];
        cnt[p]--;
        if(cnt[p]==0)
            update(p,p,0,1);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        int sz =ceil(sqrt(1.0*n));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            V.push_back(a[i]);
            pos[i]=(i-1)/sz;
        }
    
        sort(V.begin(),V.end());
        V.erase(unique(V.begin(),V.end()),V.end());
        for(int i=0;i<V.size();i++)
        {
            H[V[i]]=i+1;
            d[i+1]=V[i]%m;
        }
    
        fib[0][0]=1%m,fib[1][1]=1%m;
        for(int i=2;i<=n;i++)
        {
            fib[i][0]=(fib[i-1][0]+fib[i-2][0])%m;
            fib[i][1]=(fib[i-1][1]+fib[i-2][1])%m;
        }
        build_tree(1,n,1);
        scanf("%d",&q);
        for(int i=1;i<=q;i++)
        {
            scanf("%d%d",&Q[i].l,&Q[i].r);
            Q[i].id = i;
        }
        sort(Q+1,Q+1+q,cmp);
        int l = 1,r = 0;
        int ans=0;
        for(int i=1;i<=q;i++)
        {
            int id = Q[i].id;
            while(r<Q[i].r)
            {
                r++;
                Updata(r);
            }
            while(l>Q[i].l)
            {
                l--;
                Updata(l);
            }
            while(r>Q[i].r)
            {
                Delete(r);
                r--;
            }
            while(l<Q[i].l)
            {
                Delete(l);
                l++;
            }
            Ans[id]=tree[1].sum1;
        }
        for(int i=1;i<=q;i++)
            printf("%lld
    ",Ans[i]);
    }
  • 相关阅读:
    [eclipse]如何修改Eclipse编辑器的字体
    评CSDN上一篇讲述数据迁移的文章“程序员 12 小时惊魂记:凌晨迁移数据出大事故!”
    [Java]算术表达式组建二叉树,再由二叉树得到算式的后序和中序表达式
    [Java]算术表达式求值之三(中序表达式转二叉树方案 支持小数)
    [Java]手动构建表达式二叉树,求值,求后序表达式
    转载:构建语法树来解析数学表达式
    Oracle:Enterprise Manager 无法连接到数据库实例。下面列出了组件的状态。 以及 Oracle11g OracleDBConsoleorcl服务无法启动问题
    一个完整的企业Java项目的生命周期
    安装最新版本的Oracle公司的虚拟机软件 VirtualBox + 安装虚拟机 Windows XP 系统 + 安装 Oracle 11g 软件 + 出现 ERROR: ORA-12541: TNS:no listener 错误解决 + Oracle 11g数据库详细“卸载”步骤
    js的跨域问题 和 jQuery的跨域问题
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5224619.html
Copyright © 2011-2022 走看看