AcWing 1230. K倍区间 (前缀和)

第八届蓝桥杯省赛第十题

Problem

前缀和优化后时间N2,对于1e5的数据量依旧超时这里用一个存余数的技巧

AcWing倒师傅的题解
有了这个结论之后,我们就可以使用两层for循环来计数k倍区间的个数,但是由于数据比较大,我们不能这样做。那么我们能不能在计算前缀和的过程中同时来统计k倍区间的个数呢?当然可以。我们可以用一个数组cnt,规定cnt[i]表示当前位置之前,前缀和取模后等于i的个数,以后每出现一次前缀和(取模后)和它相等,那么k倍区间就加上cnt[sum[i]],然后cnt[sum[i]]++。这样似乎不容易理解,我们用样例举个例子。

对于数列 1 2 3 4 5,k = 2

对前1个数的和模k后为1,在此之前有0个前缀和取模后为1,总个数+0

对前2个数的和模k后为1,在此之前有1个前缀和取模后为1,总个数+1

对前3个数的和模k后为0,在此之前有0个前缀和取模后为0, 总个数+0

对前4个数的和模k后为0,在此之前有1个前缀和取模后为0,总个数+1

对前5个数的和模k后为1,在此之前有2个前缀和取模后为1,总个数+2

但是我们还忽略了一点,就是我们这样做我们少计算了区间[0,i][0,i]构成的k倍区间,其个数为cnt[0]。

作者:倒计时0天
链接:https://www.acwing.com/solution/AcWing/content/6889/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;

public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter pw = new PrintWriter(System.out);
    static int N = 100010;
    static int a[] = new int[N], S[] = new int[N], ans[] = new int[N];
    static int n, k;
    static long res;

    public static void main(String[] args) throws Exception {

        String[] s = br.readLine().split(" ");
        n = Integer.parseInt(s[0]);
        k = Integer.parseInt(s[1]);
        for (int i = 1; i <= n; i++) {
            a[i] = Integer.parseInt(br.readLine());
            S[i] = (S[i - 1] + a[i]) % k;
        }

        long res = 0;
        ans[0] = 1;
        for (int i = 1; i <= n; i++) {
            res += ans[S[i]];
            ans[S[i]]++;
        }
        pw.println(res);

        pw.flush();
        pw.close();
        br.close();
    }
}

发布了167 篇原创文章 · 获赞 3 · 访问量 3436

猜你喜欢

转载自blog.csdn.net/qq_43515011/article/details/104182433