• 2018.1.14 省选模拟赛


         挺好的一场比赛,结果被我考得像*一样.

         第一次打这种5个小时的比赛,想着时间还比较充足,就花了比较长的时间读题,预计自己应该能得40+80+50,如果中途想到了正解分数可能会更高.初步感觉T1和T3的暴力挺好打的,只是这个T2......预感到自己将花一半的时间在这道题上.

           先打T1的暴力,不到10min就打完了,测了测样例一遍就AC了,检查了一下没有发现什么问题.挺开心的,但是还是不放行,于是输出了几个中间值,发现和预期的完全不同.接着测了自己造几个小数据,都碰巧过了,但仅仅只是碰巧,中途计算的结果还是错的,如果直接这样交上去可能就没分了.于是去上了个厕所,突然想起来ST表求区间异或是错的!会把重叠部分给多统计!一开始还一直以为是ST表写错了.那么也没办法了,就打了一个线段树上去,常数大,又带一个log,当时还担心1000的数据会不会T,事实证明担心是多余的.

           T2想着暴力有80分,都没去想正解(其实是不敢想,毕竟下意识里认为我做不出省选难度的第二题嘛),结果没想到正解比暴力还简单.慢慢地1h过去了,写了300+行线段树,写到身心俱疲,心力憔悴.前60%的点我造了几组小数据都过了,结果后面20%的一直写不对.改了好长时间,大概有2h吧,到最后整个思路都混乱了,但我觉得我的做法明明就是正确的,一定不会错,再给我一点时间肯定能找到错误.果然,原来是一种情况b值的变化没有考虑到,下意识地以为和前面的相同.改过来就对了,测了好几组小数据都过了.终于放心了.然而最后的结果令人大吃一惊.我认为不可能错的恰好错了,可能错的却没错.原因是:我测试的数据全部都是小数据!当我把用大数据测时,我发现我的程序输出了好多负数,绝对是爆int了.可是我的程序里基本上全都是long long,就连读入的变量都是long long,怎么会爆int呢?于是我ctrl + F查找int,发现结构体里面有几个变量定义的是int......MDZZ.可是后20%的点还是不对啊......对于答案输出和我的输出,非常奇怪,前面一些点的输出都是一样的,到后面就完全不一样了.查错多时,无果.向老师求助,老师一眼就看出了我的错误:除法取模.MDZZ.我竟然会犯这种低级错误......当时直接写的表达式,表达式一长,取模操作就容易错,真应该听老师的话:表达式拆开来写.

           改完T2就没时间写T3了,其实T3的暴力分特别好拿,白丢了50分.匆忙写的dfs还WA掉了.发现我在写用dfs求最长路的时候忘了清零vis数组了......

    题解:

    1. 简易比特币

    题目描述

        相信大家都听说过比特币。它是一种虚拟货币,但与普通虚拟货币不同的是,它不由某个机构统一发行,而需要利用计算机找出具有特定性质的数据来“发现”货币,俗称“挖矿”。然而,由于具有这种特定性质的数据分布稀疏而无规律,因此挖矿的过程需要投入大量的计算资源来搜寻这些数据。

        仿照比特币是设计思想,我们可以设计一种简易的比特币:给定一个由n个非负整数构成的序列{ai},和一个阈值K,如果某个非空子序列(一个连续的区间)中的所有数的异或和小于K,则这个子序列就对应了一个比特币,否则它毫无价值。

           现在,给出这个序列和阈值,请你计算从中能获得多少个比特币。

        严谨起见,简要解释一下什么是异或:

    异或是一种位运算,Pascal中写作xor,C/C++中写作^。将两个数写成二进制形式,然后对每位作“相同得0、不同得1”的运算。例如,12 xor 6 = 10的运算方法如下:

    12 = (1100)2

    6   = (0110)2

    ans= (1010)2 = 10

    输入格式

           第一行包含两个整数n和K,意义如题所述;

           第二行包含n个非负整数ai,表示序列中的每一个数。

    输出格式

           一行包含一个整数,表示能从序列中获得的比特币数。

    样例输入

    3 2

    1 3 2

    样例输出

    3

    样例解释

    1 = 1

    1 xor 3 = 2

    1 xor 3 xor 2 = 0

    3 = 3

    3 xor 2 = 1

    2 = 2

    一共3个区间的异或和小于2。

    数据范围

    对于20%的数据,n≤100;

    对于40%的数据,n≤1000;

    另有20%的数据,ai≤50;

    对于100%的数据,1≤n≤105,0≤K≤109,0≤ai≤109

    分析:Trie树上一个比较神的应用.

              做这道题之前需要思考另外一道题:给定n个数,再给一个数c,问有多少数小于c.这道题可以用很多方法水过,不过一种神奇的方法是利用trie+二进制.二进制数比较大小是从高位到低位比较的.将n个数都转化为二进制,插入到trie中.然后将c在trie上跑.如果c的第i位为1,则ans += 下一步走"0"边到达的点的点权(也就是这一位是0,与c不匹配了,那么通过这一位衍生出的数都小于c),c往边"1"上走,否则c直接往边"0"上走.

              这道题也是一样的原理.只不过需要对问题转化一下.对于每个点,求出它的前缀异或值sum[i],那么对于一个区间[l,r]的异或值就是sum[r] ^ sum[l - 1],因为[1,l-1]这段区间被异或了2次,值为0,这也是一个非常重要的思想:区间上的值转化为两个端点的值.接着枚举每一个数,先统计答案再插入.假设当前插入的数的第i位为x,那么如果接下来走"x"边,那么下一位就为0,如果走"x^1"边,下一位就为1,依据上一题的原理,就可以统计了.

              部分分解法:40%,线段树预处理出区间异或值,枚举区间,区间查询. 60%,数字很小,前缀异或值的范围是0~63,那么预处理出有多少对数的异或值小于k,然后在序列中扫,统计个数(具体看代码).

    完整代码:(包含了部分分+AC代码)

     

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 100010;
    
    int n,k,a[maxn],tot = 1;
    int map[110][110],num[110];
    long long sum[maxn << 2],ans,jie[40];
    bool flag = true;
    
    struct node
    {
        int tr[3],sum;
    }e[maxn * 30];
    
    void pushup(int o)
    {
        sum[o] = sum[o * 2] ^ sum[o * 2 + 1];
    }
    
    void build(int o,int l,int r)
    {
        if (l == r)
        {
            sum[o] = a[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(o * 2,l,mid);
        build(o * 2 + 1,mid + 1,r);
        pushup(o);
    }
    
    long long query(int o,int l,int r,int x,int y)
    {
        if (x <= l && r <= y)
            return sum[o];
        int mid = (l + r) >> 1;
        long long res = 0;
        if (x <= mid)
            res = query(o * 2,l,mid,x,y);
        if (y > mid)
        {
            long long temp = query(o * 2 + 1,mid + 1,r,x,y);
            if (res == 0)
                res = temp;
            else
                res ^= temp;
        }
        return res;
    }
    
    void solve()
    {
        sum[1] = a[1];
        for (int i = 2; i <= n; i++)
        sum[i] = sum[i - 1] ^ a[i];
        for (int i = 0; i < 64; i++)
            for (int j = 0; j < 64; j++)
                if ((i ^ j) < k)
                    map[i][j] = 1;
        for (int i = 1; i <= n; i++)
        {
            for (int j = 0; j < 64; j++)
            {
                if (map[sum[i]][j])
                    ans += num[j];
            }
            if (sum[i] < k)
                ans++;
            num[sum[i]]++;
        }
        cout << ans << endl;
    }
    
    void solve2()
    {
        build(1,1,n);
        for (int i = 1; i <= n; i++)
            for (int j = i + 1; j <= n; j++)
                if (query(1,1,n,i,j) < k)
                    ans++;
        for (int i = 1; i <= n; i++)
            if (a[i] < k)
                ans++;
        cout << ans << endl;
    }
    
    void insert(long long x)
    {
        int now = 1;
        for (int i = 30; i >= 0; i--)
        {
            bool temp = x & jie[i];
            if (!e[now].tr[temp])
                e[now].tr[temp] = ++tot;
            now = e[now].tr[temp];
            e[now].sum++;
        }
    }
    
    long long query(long long x)
    {
        long long res = 0;
        int now = 1;
        for (int i = 30; i >= 0; i--)
        {
            if (now == 0)
                return res;
            bool temp = x & jie[i];
            bool temp2 = temp ^ 1;
            if (k & jie[i])
            {
                res += e[e[now].tr[temp]].sum;
                now = e[now].tr[temp2];
            }
            else
                now = e[now].tr[temp];
        }
        return res;
    }
    
    void solve3()
    {
        jie[0] = 1;
        for (int i = 1; i <= 30; i++)
            jie[i] = jie[i - 1] * 2;
        long long res = 0;
        insert(0);
        for (int i = 1; i <= n; i++)
            {
                res ^= a[i];
                ans += query(res);
                insert(res);
            }
        cout << ans << endl;
    }
    
    int main()
    {
        scanf("%d%d",&n,&k);
        for (int i = 1; i <= n; i++)
        {
            scanf("%d",&a[i]);
            if (a[i] > 50)
            flag = false;
        }
        if (flag)
        solve(); //20%
        else
            if (n <= 1000)
                solve2(); //40%
        else
            solve3();
        
        return 0;
    }

     

    2.计算

    问题描述

           我曾经的竞赛教练有一句名言:“人紧张起来的时候会变得和白痴一样的。”他总爱在比赛前重复这句话。其实论算法,他并没有教给我们多少,但是回想起以前的经历发现,至少这句话他说的真是太tm对了。用现在的话讲就是:不要怂,就是干。

    oi题很多时候都是这样,乍一看很难,越看越觉得不可做,于是安慰自己说,肯定又是我没学过的某算法,做不出很正常。但抱有这种心理的,出了考场往往会被身边的神犇打脸:“这题其实先oo一下再xx一下就好了,我太弱了搞了一小时才搞出来……”

    现在就有一道看上去似乎很不好搞的计算题,请你不怂地算一下怎么搞。

    给出一个长为N的正整数序列,有三种操作:

    A l r k b:在区间[l,r]上加上一个首项为b、公差为k的等差数列。即,序列al, al+1, al+2, al+3……变成al+b, al+1+b+k, al+2+b+2k, al+3+b+3k……

    B l r:求区间[l,r]内所有数的和mod 1000000007的值

    C l r:求区间[l,r]内所有数的平方的和mod 1000000007的值

    输入格式

             第一行包含两个数n、q,表示序列长度和操作的数量;

             第二行包含n个数{ai},表示原序列;

             接下来q行,每行包含一个操作,格式和意义如题面所述。

    输出格式

             输出若干行,每个B操作和C操作输出一行,表示询问的答案。

    样例输入

    3 3

    1 1 1

    A 1 3 2 2

    B 1 2

    C 2 3

    样例输出

    8

    74

    数据规模

    测试点1~2:n, q ≤ 1000;

    测试点3~4:k=0,没有C操作;

    测试点5~6:k=0;

    测试点7~8:没有C操作;

    对于100%的数据,n, q ≤ 100000,0 ≤ ai, k, b ≤ 109,1 ≤ l ≤ r ≤ n

    分析:部分分解法:

      20%:直接暴力.

      40%,区间加,区间求和.

      60%:区间加,区间求和,区间求平方和,把式子展开一下就好了,坑点:要先维护平方和,再维护和.

      80%:等差数列区间加,区间求和. 一个标记维护两个内容:在当前区间生效的K值和B值.标记的下传:子区间的k,b直接加上父节点的k,b,不过对于右子区间的b有变化!这是需要特别注意的一点:增加b值会有偏移!

      100%:通用方法:式子展开.看哪些信息已经维护了,哪些信息还需要维护.维护一下就好了.这里给出最终需要维护的标记:

     

     

    完整代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    const ll maxn = 100010,mod = 1000000007;
    
    ll n,q;
    bool flag1 = true,flag2 = true;
    ll a[maxn],sum[maxn << 2],tag[maxn << 2],L[maxn << 2],R[maxn << 2],sum2[maxn << 2],cnt[maxn << 2],K[maxn << 2],B[maxn << 2],inc[maxn << 2];
    
    struct node
    {
            ll id,k,b,l,r; 
    }e[maxn];
    
    ll qumo(ll a,ll b)
    {
        if (a % 2 == 0)
        a /= 2;
        else
        b /= 2;
        a %= mod;
        b %= mod;
        return a * b % mod;
    }
    
    void solve1()
    {
        for (ll i = 1; i <= q; i++)
        {
            if (e[i].id == 1)
            {
                ll temp = e[i].b;
                for (ll j = e[i].l; j <= e[i].r; j++)
                {
                    a[j] += temp;
                    a[j] %= mod;
                    temp += e[i].k;
                    temp %= mod;
                }
            }
            if (e[i].id == 2)
            {
                ll res = 0;
                for (ll j = e[i].l; j <= e[i].r; j++)
                {
                    res += a[j];
                    res %= mod;
                }
                printf("%lld
    ",res);
            }
            if (e[i].id == 3)
            {
                ll res = 0;
                for (ll j = e[i].l; j <= e[i].r; j++)
                {
                    res += a[j] * a[j] % mod;
                    res %= mod;
                }
                printf("%lld
    ",res);
            }
        }
    }
    
    void pushup(ll o)
    {
        sum[o] = (sum[o * 2] + sum[o * 2 + 1]) % mod;
        sum2[o] = (sum2[o * 2] + sum2[o * 2 + 1]) % mod;
        inc[o] = inc[o * 2] + inc[o * 2 + 1] + (R[o * 2] - L[o * 2] + 1) * sum[o * 2 + 1] % mod;
        inc[o] %= mod;
    }
    
    void build(ll o,ll l,ll r)
    {
        L[o] = l;
        R[o] = r;
        if (l == r)
        {
            sum[o] = a[l];              
            sum[o] %= mod;
            sum2[o] = a[l] * a[l] % mod;
            return;
        }
        ll mid = (l + r) >> 1;
        build(o * 2,l,mid);
        build(o * 2 + 1,mid + 1,r);
        pushup(o);
    }
    
    void pushdown(ll o)
    {
        if (tag[o])
        {
            tag[o * 2] += tag[o];
            tag[o * 2] %= mod;
            tag[o * 2 + 1] += tag[o];
            tag[o * 2 + 1] %= mod;
            ll temp1 = ((tag[o] * tag[o]) % mod) * (R[o * 2] - L[o * 2] + 1) % mod;
            sum2[o * 2] += temp1 + (2 * tag[o] * sum[o * 2])% mod;
            sum2[o * 2] %= mod;
            ll temp2 = ((tag[o] * tag[o]) % mod) * (R[o * 2 + 1] - L[o * 2 + 1] + 1) % mod;
            sum2[o * 2 + 1] += temp2 + 2 * tag[o] * sum[o * 2 + 1] % mod;
            sum2[o * 2 + 1] %= mod;
            sum[o * 2] += tag[o] * (R[o * 2] - L[o * 2] + 1) % mod;
            sum[o * 2] %= mod;
            sum[o * 2 + 1] += tag[o] * (R[o * 2 + 1] - L[o * 2 + 1] + 1) % mod;
            sum[o * 2 + 1] %= mod;
            tag[o] = 0;
        }
    }
    
    void update(ll o,ll l,ll r,ll x,ll y,ll v)
    {
        if (x <= l && r <= y)
        {
            tag[o] += v;
            tag[o] %= mod;
            ll temp = ((v * v) % mod) * (r - l + 1) % mod;
            sum2[o] += temp + 2 * v * sum[o] % mod;
            sum2[o] %= mod;
            sum[o] += v * (r - l + 1) % mod;
            sum[o] %= mod;
            return;
        }
        pushdown(o);
        ll mid = (l + r) >> 1;
        if (x <= mid)
            update(o * 2,l,mid,x,y,v);
        if (y > mid)
            update(o * 2 + 1,mid + 1,r,x,y,v);
        pushup(o);
    }
    
    ll query(ll o,ll l,ll r,ll x,ll y)
    {
        if (x <= l && r <= y)
            return sum[o];
        pushdown(o);
        ll mid = (l + r) >> 1;
        ll res = 0;
        if (x <= mid)
            res += query(o * 2,l,mid,x,y);
        res %= mod;
        if (y > mid)
            res += query(o * 2 + 1,mid + 1,r,x,y);
        res %= mod;
        return res;
    }
    
    ll query2(ll o,ll l,ll r,ll x,ll y)
    {
        if (x <= l && r <= y)
            return sum2[o];
        pushdown(o);
        ll mid = (l + r) >> 1;
        ll res = 0;
        if (x <= mid)
            res += query2(o * 2,l,mid,x,y);
        res %= mod;
        if (y > mid)
            res += query2(o * 2 + 1,mid + 1,r,x,y);
        res %= mod;
        return res;
    }
    
    void solve2()
    {
        build(1,1,n);
        for (ll i = 1; i <= q; i++)
        {
            if (e[i].id == 2)
                printf("%lld
    ",query(1,1,n,e[i].l,e[i].r));
            else
                if (e[i].id == 1)
                    update(1,1,n,e[i].l,e[i].r,e[i].b);
                else
                    if (e[i].id == 3)
                        printf("%lld
    ",query2(1,1,n,e[i].l,e[i].r));
        }
    }
    
    void pushdown2(ll o)
    {
        if (cnt[o] != 0)
        {
            cnt[o * 2] = cnt[o * 2 + 1] = 1;
            cnt[o] = 0;
            K[o * 2] += K[o];
            K[o * 2] %= mod;
            K[o * 2 + 1] += K[o];
            K[o * 2 + 1] %= mod;
            B[o * 2] += B[o];
            B[o * 2] %= mod;
            B[o * 2 + 1] += (B[o] + ((R[o * 2] - L[o * 2] + 1) * K[o] % mod)) % mod;
            B[o * 2 + 1] %= mod;
            ll tempp = qumo(B[o] + B[o] + (R[o * 2] - L[o * 2]) * K[o],R[o * 2] - L[o * 2] + 1);
            sum[o * 2] += tempp;
            sum[o * 2] %= mod;
            ll temp = (B[o] + ((R[o * 2] - L[o * 2] + 1) * K[o] % mod)) % mod; //右半区间的b 
            tempp = qumo(temp + temp + (R[o * 2 + 1] - L[o * 2 + 1]) * K[o],R[o * 2 + 1] - L[o * 2 + 1] + 1);
            sum[o * 2 + 1] += tempp;
            sum[o * 2 + 1] %= mod;
            K[o] = 0;
            B[o] = 0;
        }
    }
    
    void update2(ll cur,ll o,ll l,ll r,ll x,ll y,ll k,ll b)
    {
        if (x <= l && r <= y)
        {
            cnt[o] = 1;
            K[o] += k;
            K[o] %= mod;
            b = b + (l - e[cur].l) * k % mod;
            b %= mod;
            B[o] += b;
            B[o] %= mod;
            ll res1 = (r - l) * k + b + b;
            ll res2 = r - l + 1;
            if (res1 % 2 == 0)
            res1 /= 2;
            else
            res2 /= 2;
            res1 %= mod;
            res2 %= mod;
            ll temp = qumo(b + b + ((r - l) * k),(r - l + 1));
            temp %= mod;
            sum[o] += temp;
            sum[o] %= mod;
            return;
        }
        pushdown2(o);
        ll mid = (l + r) >> 1;
        if (x <= mid)
            update2(cur,o * 2,l,mid,x,y,k,b);
        if (y > mid)
            update2(cur,o * 2 + 1,mid + 1,r,x,y,k,b);
        pushup(o);
    }
    
    ll query3(ll o,ll l,ll r,ll x,ll y)
    {
        if (x <= l && r <= y)
            return sum[o];
        pushdown2(o);
        ll res = 0;
        ll mid = (l + r) >> 1;
        if (x <= mid)
            res += query3(o * 2,l,mid,x,y);
        res %= mod;
        if (y > mid)
            res += query3(o * 2 + 1,mid + 1,r,x,y);
        res %= mod;
        return res;
    }
    
    void solve3()
    {
        build(1,1,n);
        for (ll i = 1; i <= q; i++)
        {
            if (e[i].id == 2)
                printf("%lld
    ",query3(1,1,n,e[i].l,e[i].r));
            else
                update2(i,1,1,n,e[i].l,e[i].r,e[i].k,e[i].b);
        }
    }
    
    void pushdown3(ll o)
    {
        if (cnt[o] != 0)
        {
            cnt[o * 2] = cnt[o * 2 + 1] = 1;
            cnt[o] = 0;
            K[o * 2] += K[o];
            K[o * 2] %= mod;
            K[o * 2 + 1] += K[o];
            K[o * 2 + 1] %= mod;
            B[o * 2] += B[o];
            B[o * 2] %= mod;
            B[o * 2 + 1] += (B[o] + ((R[o * 2] - L[o * 2] + 1) * K[o] % mod)) % mod;
            B[o * 2 + 1] %= mod;
            //史上最痛苦的时刻:
            ll len1 = (R[o * 2] - L[o * 2] + 1),len2 = (R[o * 2 + 1] - L[o * 2 + 1] + 1);
            ll tempp =  (B[o] + ((R[o * 2] - L[o * 2] + 1) * K[o] % mod)) % mod; //右半部分的b!
            ll temp = 2 * B[o] * sum[o * 2] % mod;
            temp = (temp + 2 * K[o] * inc[o * 2] % mod) % mod;
            temp = (temp + B[o] * B[o] % mod * len1 % mod) % mod;
            temp = (temp + K[o] * B[o] % mod * (len1 - 1) % mod * len1 % mod) % mod;
            ll temp2 = (len1 - 1) * len1 * (2 * len1 - 1) / 6 % mod;
            temp2 = temp2 * K[o] % mod * K[o] % mod;
            temp = (temp + temp2) % mod;
            sum2[o * 2] = (sum2[o * 2] + temp) % mod;
            temp = temp2 = 0;
            
            ll k = K[o],b = tempp;
            temp = 2 * b * sum[o * 2 + 1] % mod;
            temp = (temp + 2 * k * inc[o * 2 + 1] % mod) % mod;
            temp = (temp + b * b % mod * len2 % mod) % mod;
            temp = (temp + k * b % mod * (len2 - 1) % mod * len2 % mod) % mod;
            temp2 = (len2 - 1) * len2 * (2 * len2 - 1) / 6 % mod;
            temp2 = temp2 * k % mod * k % mod;
            temp = (temp + temp2) % mod;
            sum2[o * 2 + 1] = (sum2[o * 2 + 1] + temp) % mod;
            temp = temp2 = 0;
            
            b = B[o],k = K[o];
            temp = b * len1 % mod;
            temp2 = (len1 - 1) * len1 / 2 % mod;
            temp2 = temp2 * k % mod;
            temp = (temp + temp2) % mod;
            sum[o * 2] = (sum[o * 2] + temp) % mod;
            temp = temp2 = 0;
            
            b = tempp,k = K[o];
            temp = b * len2 % mod;
            temp2 = (len2 - 1) * len2 / 2 % mod;
            temp2 = temp2 * k % mod;
            temp = (temp + temp2) % mod;
            sum[o * 2 + 1] = (sum[o * 2 + 1] + temp) % mod;
            temp = temp2 = 0;
            
            k = K[o],b = B[o];
            temp = (len1 - 1) * len1 / 2 % mod;
            temp = temp * b % mod;
            temp2 = (len1 - 1) * len1 * (2 * len1 - 1) / 6 % mod;
            temp2 = temp2 * k % mod;
            temp = (temp + temp2) % mod;
            inc[o * 2] = (inc[o * 2] + temp) % mod;
            temp = temp2 = 0;
            
            k = K[o],b = tempp;
            temp = (len2 - 1) * len2 / 2 % mod;
            temp = temp * b % mod;
            temp2 = (len2 - 1) * len2 * (2 * len2 - 1) / 6 % mod;
            temp2 = temp2 * k % mod;
            temp = (temp + temp2) % mod;
            inc[o * 2 + 1] = (inc[o * 2 + 1] + temp) % mod;
            temp = temp2 = 0; 
            B[o] = K[o] = 0; 
        }
    }
    
    void update3(ll cur,ll o,ll l,ll r,ll x,ll y,ll k,ll b)
    {
        if (x <= l && r <= y)
        {
            b = b + (l - e[cur].l) * k % mod;
            b %= mod;
            cnt[o] = 1;
            K[o] += k;
            K[o] %= mod;
            B[o] += b;
            B[o] %= mod;
            ll temp = 2 * b * sum[o] % mod;
            temp = (temp + 2 * k * inc[o] % mod) % mod;
            temp = (temp + b * b % mod * (r - l + 1) % mod) % mod;
            temp = (temp + k * b % mod * (r - l) % mod * (r - l + 1) % mod) % mod;
            ll len = r - l + 1;
            ll temp2 = (len - 1) * len * (2 * len - 1) / 6;
            temp2 %= mod;
            ll temp3 = k * k % mod;
            temp = (temp + temp2 * temp3 % mod) % mod;
            sum2[o] += temp;
            sum2[o] %= mod;
            temp = b * len % mod;
            temp2 = (len - 1) * len / 2;
            temp2 %= mod;
            temp2 = temp2 * k % mod;
            temp = (temp + temp2) % mod;
            sum[o] += temp;
            sum[o] %= mod;
            temp2 = (len - 1) * len / 2;
            temp2 %= mod;
            temp2 = temp2 * b % mod;
            temp = temp2;
            temp2 = (len - 1) * len * (2 * len - 1) / 6;
            temp2 %= mod;
            temp2 = temp2 * k % mod;
            temp = (temp + temp2) % mod;
            inc[o] += temp;
            inc[o] %= mod;
            return;
        }
        pushdown3(o);
        ll mid = (l + r) >> 1;
        if (x <= mid)
            update3(cur,o * 2,l,mid,x,y,k,b);
        if (y > mid)
            update3(cur,o * 2 + 1,mid + 1,r,x,y,k,b);
        pushup(o);
    }
    
    ll query4(ll o,ll l,ll r,ll x,ll y)
    {
        if (x <= l && r <= y)
        return sum[o];
        pushdown3(o);
        ll res = 0;
        ll mid = (l + r) >> 1;
        if (x <= mid)
            res += query4(o * 2,l,mid,x,y);
        res %= mod;
        if (y > mid)
            res += query4(o * 2 + 1,mid + 1,r,x,y);
        res %= mod;
        return res;
    }
    
    ll query5(ll o,ll l,ll r,ll x,ll y)
    {
        if (x <= l && r <= y)
        return sum2[o];
        pushdown3(o);
        ll res = 0;
        ll mid = (l + r) >> 1;
        if (x <= mid)
        res += query5(o * 2,l,mid,x,y);
        res %= mod;
        if (y > mid)
        res += query5(o * 2 + 1,mid + 1,r,x,y);
        res %= mod;
        return res;
    }
    
    void solve4()
    {
        build(1,1,n);
        for (int i = 1; i <= q; i++)
        {
            if (e[i].id == 1)
                update3(i,1,1,n,e[i].l,e[i].r,e[i].k,e[i].b);
            else
                if (e[i].id == 2)
                    printf("%lld
    ",query4(1,1,n,e[i].l,e[i].r));
            else
                printf("%lld
    ",query5(1,1,n,e[i].l,e[i].r));
        }
    }
    
    int main()
    {
        scanf("%lld%lld",&n,&q);
        for (ll i = 1; i <= n; i++)
            scanf("%lld",&a[i]);
        for (ll i = 1; i <= q; i++)
        {
            char ch[2];
            scanf("%s",ch);
            if (ch[0] == 'A')
               {
                    e[i].id = 1;
                    scanf("%lld%lld%lld%lld",&e[i].l,&e[i].r,&e[i].k,&e[i].b);
                    if (e[i].k != 0)
                        flag1 = false;
               }
            if (ch[0] == 'B')
            {
                e[i].id = 2;
                scanf("%lld%lld",&e[i].l,&e[i].r);
            }
            if (ch[0] == 'C')
            {
                e[i].id = 3;
                flag2 = false;
                scanf("%lld%lld",&e[i].l,&e[i].r);
            }
        }
        if (n <= 1000 && q <= 1000)
           solve1();
        else
            if (flag1 && flag2)
                solve2();
        else
            if (flag1)
                solve2();
        else
            if (flag2)
            solve3();
        else
            solve4();
        
        return 0;   
    }

    3. 路径

    问题描述

    实在不知道怎么编题面了,就写得直白一点吧。反正没几个人写得完三题,估计都看不到这里。

    给出一个仙人掌图,求图中最长路的长度。

    Emmm……还是稍微具体一点吧。

    仙人掌图是指一个有N个点与M条边的无向图,点从1到N标号,每条边有各自的长度,图中可能存在若干个简单环,但是,每个点最多只会属于1个简单环路。简单环是指一个经过至少两个点、且不经过重复点的环。(这里仙人掌图的定义也许和你在别处见过的不太一样,请仔细审题)

    例如,图1所示的是一个仙人掌图,但图2则不是,因为3号点同属于两个简单环。

     

    图1

     

    图2

    给出一个仙人掌图,你需要求出图中的最长路的长度。最长路不能经过重复的点。例如,假设图中所有边长度都为1的话,图1中的仙人掌图的一条最长路为1-2-3-4-5-6,长度为5。

     

    输入格式

           第一行包含1个整数Q,表示数据组数;

           每组数据的第一行2个整数N,M,表示仙人掌图的点数和边数;

           每组数据的接下来M行,每行3个正整数x,y,z,描述一条连接点x与点y,长度为z的边。

          

    输出格式

           对于每组数据输出一行,每行包含一个整数,表示最长路径的长度。

    样例输入

    2

    6 7

    1 2 1

    2 3 1

    3 1 1

    3 4 1

    4 5 1

    5 6 1

    6 4 1

    4 4

    1 2 1

    2 3 2

    3 4 3

    4 1 4

    样例输出

    5

    9

     

    数据规模

    对于10%的数据,Q ≤ 5,n ≤ 10;

    另有20%的数据,满足n=m+1;

    另有20%的数据,满足n=m;

    另有20%的数据,满足每个环上的点数≤ 20;

    对于100%的数据,Q ≤ 1000, 所有测试点的n之和 ≤ 100,000,z≤ 1000。

    分析:思路同:bzoj1023,只不过边权不再是1,并且也没有了“距离”的概念,那么所有地方直接取max就好了,不必在环上走过的长度取min.环上的部分特别容易写错,需要引起注意.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 300010;
    
    int Q,n,m,head[maxn],to[maxn],w[maxn],tot = 1,nextt[maxn];
    int deep[maxn],pos[maxn],pre[maxn],low[maxn],dfs_clock;
    int ans,f[maxn],fa[maxn],cnt,a[maxn],sum[maxn],l,r;
    
    void init()
    {
        memset(head,0,sizeof(head));
        tot = 1;
        memset(deep,0,sizeof(deep));
        memset(pre,0,sizeof(pre));
        memset(low,0,sizeof(low));
        dfs_clock = 0;
        ans = 0;
        memset(f,0,sizeof(f));
        memset(fa,0,sizeof(fa));
        cnt = 0;
        l = r = 1;
    }
    
    void add(int x,int y,int z)
    {
        w[tot] = z;
        to[tot] = y;
        nextt[tot] = head[x];
        head[x] = tot++;
    }
    
    void solve(int x,int y)
    {
        memset(a,0,sizeof(a));
        memset(pos,0,sizeof(pos));
        cnt = deep[y] - deep[x] + 1;
        for (int i = y; i != x; i = fa[i])
            a[cnt--] = i;
        a[cnt] = x;
        cnt = deep[y] - deep[x] + 1;
        for (int i = 1; i <= cnt; i++)
        {
            a[cnt + i] = a[i];
            for (int j = head[a[i]];j;j = nextt[j])
            {
                int v = to[j];
                if (v == a[i + 1])
                {
                    sum[i + 1] = w[j];
                    break;
                }
            }
        }
        for (int i = 2; i <= cnt; i++) //不能从1复制,因为上面在处理i=cnt的时候已经处理了sum[cnt + 1].
            sum[i + cnt] = sum[i];
        for (int i = 1; i <= cnt * 2; i++)
            sum[i] += sum[i - 1];
        l = 1,r = 0;
        for (int i = 1; i <= cnt * 2; i++)
        {
            while (l <= r && i - pos[l] >= cnt)
                l++;
            ans = max(ans,f[a[pos[l]]] + f[a[i]] + sum[i] - sum[pos[l]]);
            while (l <= r && f[a[pos[r]]] - sum[pos[r]] <= f[a[i]] - sum[i])
                r--;
            pos[++r] = i;
        }
        for (int i = 2; i <= cnt; i++)
            f[x] = max(f[x],f[a[i]] + max(sum[i],sum[cnt + 1] - sum[i]));
    }
    
    void dfs(int u,int faa)
    {
        pre[u] = low[u] = ++dfs_clock;
        for (int i = head[u];i;i = nextt[i])
        {
            int v = to[i];
            if (v == faa)
                continue;
            if (!pre[v])
            {
                deep[v] = deep[u] + 1;
                fa[v] = u;
                dfs(v,u);
                low[u] = min(low[u],low[v]);
            }
            else
                low[u] = min(low[u],pre[v]);
            if (pre[u] < low[v])
            {
                ans = max(ans,f[u] + f[v] + w[i]);
                f[u] = max(f[u],f[v] + w[i]);
            }
        }
        for (int i = head[u];i;i = nextt[i])
        {
            int v = to[i];
            if (v == faa)
                continue;
            if (fa[v] != u && pre[u] < pre[v])
                solve(u,v);
        }
    }
    
    int main()
    {
        scanf("%d",&Q);
        while (Q--)
        {
            init();
            scanf("%d%d",&n,&m);
            for (int i = 1; i <= m; i++)
            {
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                add(x,y,z);
                add(y,x,z);
            }
            dfs(1,0);
            printf("%d
    ",ans);
        }
    
        return 0;
    }

    最初的暴力还写错了:

    void dfs(int u,int dis)
    {
        ans = max(ans,dis);
        vis[u] = 1;
        for (int i = head[u];i;i = nextt[i])
        {
            int v = to[i];
            if (!vis[v])
                dfs(v,dis + w[i]);
        }
    }

    如果改成下面这样就对了:

    void dfs(int u,int dis)
    {
        ans = max(ans,dis);
        vis[u] = 1;
        for (int i = head[u];i;i = nextt[i])
        {
            int v = to[i];
            if (!vis[v])
                dfs(v,dis + w[i]);
        }
        vis[u] = 0;  
    }

    vis数组没有清零,u这个点可能会有多条路径经过.最后写急了没有考虑到这一点.

    教训:

      1.把握好时间,给后面的题目留充足的时间,对于一些难写的题目,要预估写好的时间.

      2.不要不敢写正解,有时候正解比暴力还要容易.

      3.代码习惯:如果一个地方可能会爆int,那么在内存不是很紧的情况下,所有变量用long long.

      4.表达式拆开来写.

      5.学会造大数据来对拍,有时候小数据找不出错误来.

  • 相关阅读:
    对Spark硬件配置的建议
    Hadoop调优 | NameNode主备宕机引发的思考
    系统解析Apache Hive
    Spark集群和任务执行
    Redis中的一致性哈希问题
    Java并发队列与容器
    重要 | Spark和MapReduce的对比,不仅仅是计算模型?
    Redis从入门到精通
    LeaFlet自定义控件
    java学习的一些琐碎知识点
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8303866.html
Copyright © 2020-2023  润新知