• 【被迫营业7】数形结合


    numbergraph.pdf

    Solution得等会。

    Solution

    • (20\%,opt in {+,-})
      这个水,无论从哪个点开始的值都是一样的,只要随便找一个点跑一遍输出既可。
      (mathcal{O}(n))

    • (10\%,n le 1000)
      这个照样水,枚举起点然后暴力算出其(F(x))值,取最大既可。
      (mathcal{O}(n ^ 2))

    • (10\%,opt in {+, imes})
      这有啥用啊,反正我是没想到
      我瞎写的,不会真有人不会正解能拿这个部分分吧/jk/jk/jk

    • (mathcal{O}(nsqrt{n}))做法
      我们对边(E)集合分块,每个整块长度为(sqrt{n}),对每个块进行一下运算,变成一个(ax+b)的形式(也就是说一个数(x)进到这个块里运算的时候会变成(ax+b),相当于整个块的变换),跑一遍,总复杂度为(mathcal{O}(n))
      然后枚举起点,如果接下来的运算是一个完整的块,那么是(mathcal{O}(1))的,否则就暴力一下,最坏(mathcal{O}(sqrt{n}))
      显然是(mathcal{O}(nsqrt{n}))的复杂度,瓶颈在运算那边。

    std使用了破环成链的方法,便于模拟。

    # include <bits/stdc++.h>
    using namespace std;
    const int N = 100005;
    int n;
    struct edge
    {
        char opt;
        long long x;
        int soc;
    }E[N << 1];
    
    struct node
    {
        long long mul,add;
    }a[N << 1]; 
    
    int len,num;
    
    int belong(int x)
    {
        if(x <= n) return (x - 1) / len + 1;
        else 
        {
            x -= n;
            return (x - 1) / len + 1 + num;
        }
    }
    int l[1005],r[1005];
    
    void update(long long &x,int i)
    {
        if(E[i].opt == '+') x += E[i].x;
        else x *= E[i].x;
        return;
    }
    
    long long solve(int X)
    {
        int now = X,cnt = 0;
        long long ans = 1;
        int R = X + n - 1;
        while(now <= R)
        {
            bool flag = 1;
            int _l,_r;
            if(now != l[belong(now)]) 
            {
                flag = 0;
                _l = now;
            }
            else _l = l[belong(now)];
            if(r[belong(_l)] > R)
            {
                _r = R;
                flag = 0;
            }
            else _r = r[belong(_l)];
            if(!flag)
            {
                for(int i = _l; i <= _r; i++)
                {
                    update(ans,i);
                }
                now = _r + 1;
            }
            else
            {
                ans = ans * a[belong(_l)].mul + a[belong(_l)].add;
                now = _r + 1;
            }
        }
        return ans;
    
    }
    
    int main(void)
    {
        freopen("exin.in","r",stdin);
        freopen("out1.out","w",stdout);
        scanf("%d",&n);
        for(int i = 1; i <= n; i++)
        {
            cin >> E[i].opt;
            scanf("%lld",&E[i].x);
            if(E[i].opt == '-') 
            {
                E[i].opt = '+';
                E[i].x = -E[i].x;
            }
            E[i].soc = i;
            E[i + n] = E[i];
        }
        len = sqrt(n),num = (n - 1) / len + 1;
        for(int i = 1; i <= num; i++) 
        {
            l[i] = (i - 1) * len + 1;
            r[i] = i * len;
            a[i].mul = 1,a[i].add = 0;
        }
        r[num] = n;
        for(int i = num + 1; i <= 2 * num; i++)
        {
            l[i] = l[i - num] + n;
            r[i] = r[i - num] + n;
            a[i].mul = 1,a[i].add = 0;
        }
        for(int i = 1; i <= num * 2; i++)
        {
            for(int j = l[i]; j <= r[i]; j++)
            {
                if(E[j].opt == '+') 
                {
                    a[i].add += E[j].x;
                }
                else 
                {
                    a[i].mul *= E[j].x;
                    a[i].add *= E[j].x;
                }
            }
        }
        long long ans = -1e9;
        for(int i = 1; i <= n; i++)
        {
            long long _s = solve(i);
            ans = max(ans,_s);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
    • (mathcal{O}(nlog{n}))做法
      by zps(LightningUZ).

    其实差不多,破环成链,其实(F(x))就等于(E_x)(E_{x + n})运算一遍,显然可以线段树维护求和。时间复杂度为(mathcal{O}(nlog{n}))

    对于两个区间((mul_1,add_1),(mul_2,add_2))合并:

    [mul_2(mul_1 x + add_1) + add_2\ = mul_1 mul_2 x + mul_2 add_1 + add_2 ]

    所以新的(mul = mul_1mul_2,add = mul_2add_1+add_2)

    # include <bits/stdc++.h>
    using namespace std;
    const int N = 100005;
    struct node 
    {
        long long mul,add;
    }T[N << 2];
    struct edge
    {
        char opt;
        long long x;
    }E[N << 1];
    int n;
    
    void build(int root,int l,int r)
    {
        T[root].mul = 1;
        T[root].add = 0;
        if(l == r)
        {
            if(E[l].opt == 'x') 
            {
                T[root].mul *= E[l].x;
                T[root].add *= E[l].x;
            }
            else
            {
                T[root].add += E[l].x;
            }
            return;
        }
        int mid = (l + r) >> 1;
        build(root << 1,l,mid);
        build(root << 1 | 1,mid + 1,r);
        T[root].mul = T[root << 1].mul * T[root << 1 | 1].mul;
        T[root].add = T[root << 1].add * T[root << 1 | 1].mul + T[root << 1 | 1].add;
        if(T[root].mul == 0) T[root].mul = 1;
        return;
    }
    
    node query(int root,int l,int r,int s,int t)
    {
        if(l <= s && t <= r)
        {
            return T[root];
        }
        int mid = (s + t) >> 1;
        node L,R;
        L.mul = 1,L.add = 0;
        R.mul = 1,R.add = 0;
        if(l <= mid) L = query(root << 1,l,r,s,mid);
        if(r > mid) R = query(root << 1 | 1,l,r,mid + 1,t);
        if(L.mul == 0) L.mul = 1;
        if(R.mul == 0) R.mul = 1;
        node ans;
        ans.mul = 1,ans.add = 0;
        ans.mul = L.mul * R.mul;
        ans.add = L.add * R.mul + R.add;
        // printf("lmul = %lld,ladd = %lld,rmul = %lld,radd = %lld
    ",L.mul,L.add,R.mul,R.add);
        // printf("ansmul = %lld,ansadd = %lld
    ",ans.mul,ans.add);
        return ans;
    }
    
    void print(int root,int l,int r)
    {
        int mid = (l + r) >> 1;
        if(l != r) print(root << 1,l,mid);
        if(l != r) print(root << 1 | 1,mid + 1,r);
        printf("T[%d] : mul = %lld,add = %lld,l = %d,r = %d
    ",root,T[root].mul,T[root].add,l,r);
    }
    
    int main(void)
    {
        freopen("exin.in","r",stdin);
        freopen("out2.out","w",stdout);
        scanf("%d",&n);
        for(int i = 1; i <= n; i++)
        {
            cin >> E[i].opt;
            scanf("%lld",&E[i].x);
            if(E[i].opt == '-') 
            {
                E[i].opt = '+';
                E[i].x = -E[i].x;
            }
        }
        for(int i = 1; i <= n; i++)
        {
            E[i + n] = E[i];
        }
        for(int i = 1; i <= (n << 2); i++) 
        {
            T[i].mul = 1,T[i].add = 0;
        }   
        build(1,1,n + n);
        // print(1,1,2 * n);
        long long ans = -1e9;
        for(int i = 1; i <= n; i++)
        {
            node A = query(1,i,i + n - 1,1,n * 2);
            // printf("i = %d,mul = %lld,add = %lld
    ",i,A.mul,A.add);
            ans = max(ans,A.mul + A.add);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
    • (mathcal{O}(n))做法
      by zps(LightningUZ).

    单调区间求和trick,具体私聊zps.

    总结:ZPS就是强啊!

  • 相关阅读:
    [hdu5400 Arithmetic Sequence]预处理,容斥
    [hdu5399 Too Simple]YY
    [hdu5396 Expression]区间DP
    [hdu5392 Infoplane in Tina Town]置换的最小循环长度,最小公倍数取模,输入挂
    [bzoj2038 [2009国家集训队]小Z的袜子(hose)] 莫队算法
    [hdu1506 Largest Rectangle in a Histogram]笛卡尔树
    hdu5381 The sum of gcd]莫队算法
    [hdu5389 Zero Escape]数根的性质,DP
    [hdu5387 Clock]时钟夹角问题
    [CodeForces 300D Painting Square]DP
  • 原文地址:https://www.cnblogs.com/luyiming123blog/p/14315062.html
Copyright © 2020-2023  润新知