zoukankan      html  css  js  c++  java
  • CSP-SJX2019 和积和

    题目链接

    Solution

    考虑每个数 (a_i) 对答案的贡献:若 (b) 中存在一个区间 ([l,r]) ((l leq i leq r)),则该区间的和 (sum_{l,r}) 必定会与 (a_i) 相乘恰好一次,并对答案产生相应的贡献。

    现在问题转化为:对于每个下标 (i),求出 (b) 中所有包含该下标的区间(mathrm{sum}) 和(记为 (S_i)

    例如样例一,(b) 中所有包含下标 (2) 的区间为 ([1,2])([1,3])([2,2])([2,3]),它们的 (mathrm{sum}) 值依次为 (3+4=7)(3+4+5=12)(4=4)(4+5=9). (S_2=7+12+4+9=32). 所以 (a_2) 对答案产生的贡献为 (32*3=96).

    尝试用 (mathrm{O(n)}) 的时间复杂度求出每个下标 (i)(S) 值。设 (f_i)(b) 中以 (i)左端点的区间的 (mathrm{sum}) 和,(g_i)(b) 中以 (i)右端点的区间的 (mathrm{sum}) 和。得到递推式:

    (f_i=f_{i+1}+b_i imes (n-i+1))

    (g_i=g_{i-1}+b_i imes i)

    设位置 (i)(S) 值为 (S_i),有: (S_i=S_{i-1}+f_i-g_{i-1}). 其中 (g_{i-1}) 表示两端都在 (i) 左边的多余区间。

    (ans=sum_{i=1}^n) (S_i imes a_i). 总复杂度 (mathrm{O(n)}).

    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N = 2333333, mod = 1000000007;
    long long n, ans = 0, g[N], f[N], S[N], a[N], b[N];
    int main()
    {
        scanf("%lld", &n);
        g[0] = S[0] = f[n + 1] = 0;
        for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
        for(int i = 1; i <= n; i++) scanf("%lld", &b[i]);
        for(int i = n; i >= 1; i--)
            f[i] = (f[i + 1] % mod + (b[i] * (n - i + 1)) % mod) % mod;
        for(int i = 1; i <= n; i++)
            g[i] = (g[i - 1] % mod + (b[i] * i) % mod) % mod;
        for(int i = 1; i <= n; i++)
        {
            S[i] = (S[i - 1] + f[i] - g[i - 1] + mod) % mod;
            ans = (ans + (a[i] * S[i]) % mod) % mod;
        }
        printf("%lld", ans);
        return 0;
    } 
    
  • 相关阅读:
    杯具,丢失了一部分邮件
    Android Building System 总结
    build/envsetup.sh
    PhoneApp是什么时候被创建的
    测试电信的WAP PUSH的方法
    修改Activity响应音量控制键修改的音频流
    ril崩溃时的出错地址定位
    java interface 强制类型转换小记
    android 修改系统程序图标大小
    git 合并patch的方法
  • 原文地址:https://www.cnblogs.com/Andy-park/p/14074430.html
Copyright © 2011-2022 走看看