【牛客编程巅峰赛S2第4场 - 钻石&王者】交叉乘

交叉乘

题目描述

上小学二年级的牛牛已经精通整数的加法和乘法。现在你要考考他。你先给出一个整数数组​a ,然后每次你会给一对整数l,r(l≤r),牛牛需要算出

∑ i = l r \sum_{i=l}^r i=lr ∑ j = i + 1 r \sum_{j=i+1}^r j=i+1r a i a_i ai * a j a_j aj
的值。

但是牛牛算完之后你不能不确定他算得对不对,为了验证他的答案,你决定自己算一遍。
为了不输出过大的答案,假设答案为ans,请输出ans % 1,000,000,007。

题解

这道题是要我们遍历求和,看了数据范围以后发现,直接暴力一定会超时,因为我们做了很多重复的计算。

所以可以使用前缀和进行一波优化,使用新数组对前缀和存储。

其次我们要做的是对原式进行化简:

我们设 c u r [ i ] = cur[i]= cur[i]= ∑ k = 0 n a k \sum_{k=0}^n a_k k=0nak 则可以将原式转换为:

∑ i = l r \sum_{i=l}^r i=lr a i a_i ai ∗ * ( c u r [ r ] − c u r [ i ] ) (cur[r] - cur[i]) (cur[r]cur[i])

由分配律可得到

∑ i = l r \sum_{i=l}^r i=lr a i ∗ c u r [ r ] a_i * cur[r] aicur[r] − - ∑ i = l r \sum_{i=l}^r i=lr a i ∗ c u r [ i ] a_i * cur[i] aicur[i]

可以设 p [ i ] = p[i] = p[i]= ∑ k = 1 i \sum_{k=1}^i k=1i a k ∗ c u r [ k ] a_k * cur[k] akcur[k]

最后 原式可化简为
= = = ( c u r [ r ] − c u r [ l − 1 ] ) ∗ c u r [ r ] − ( p [ r ] − p [ l − 1 ] ) (cur[r]-cur[l-1]) * cur[r] - (p[r] -p[l-1]) (cur[r]cur[l1])cur[r](p[r]p[l1])

代码

    private long[] cur = new long[100100];
    private long[] p = new long[100100];
    private long[] k = new long[100100];
    private long[] arr = new long[100100];
    private long mod = 1000000007;

    public int[] getSum (int[] a, int[] query) {
        // write code here
        int n = a.length;
        int[] ans = new int[query.length/2];
        int in = 0;
        for(int i = 1;i <= n; i++) {
             k[i] = a[i-1];
        }
        for(int i = 1;i <= n; i++) {
            cur[i] = (cur[i-1] + k[i])%mod;
        }
        for (int i=1;i<=n;i++) {
            arr[i]=k[i]*cur[i]%mod;
        }
        for (int i=1;i<=n;i++) {
            p[i]=(p[i-1]+arr[i])%mod;
        }
        for(int i = 0;i < query.length; i+=2) {
            int l = query[i], r = query[i+1];
            long vv = ((cur[r] - cur [l-1]) * cur[r] % mod + mod - (p[r]-p[l-1]))%mod;
            vv += mod;
            vv %= mod;
            ans[in++] = (int) vv;
        }
        return ans;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值