zoukankan      html  css  js  c++  java
  • 问题 E: 求方案

    题目描述
    有n个正整数排成一行。你的目的是要从中取出一个或连续的若干个数,使它们的和能够被k整除。
    例如,有6个正整数,它们依次为1,2,6,3,7,4。若k=3,则你可以取出1,2,6,或者2,6,3,7,也可以仅仅取出一个6或者3使你所取的数之和能被3整除。当然,满足要求的取法不止以上这4种。事实上,一共有7种取法满足要求。
    给定n和k,以及这n个数。你的任务就是确定从这n个数中取出其中一个数或者若干连续的数,使它们的和能被k整除有多少方法。记Ha=1234567,由于取法可能很多,因此你只需要输出它mod Ha的值即可

    输入
    第一行为两个整数n,k。以下n行每行一个正整数,描述这个序列。

    输出
    输出一个整数,为答案mod Ha的结果。

    样例输入
    复制样例数据
    6 3
    1
    2
    6
    3
    7
    4
    样例输出
    7

    首先要求一段和是k的倍数, 那么首先想到的肯定是利用前缀和sum[i] ,求前缀和, 然后区间和就是sum[j] - sum[i - 1]. j , i ∈(1 , n) , 那么只要(sum[j] - sum[i - 1]) % k == 0 , 那么这个就是一个成功的方案, 那么这个公式又表示什么呢, 两个前缀和相减是k的倍数,不就是这两个前缀和同余嘛, 可以简单的化简一下,就出来了, 令sum[j] = ka + t1 , sum[i - 1] = kb + t2 , 那么为了满足这个公式就是k(a - b) + t1 - t2 是k的倍数, 此时此刻t1 + t2 == 0 , 即两个前缀和同余,
    由此我们可以随便用两个sum % k 相等的数构成一个区间和,并且这个区间和肯定满足题目给的条件,那么我们就存一下sum % k 有多少个相同 , num[sum % k] ++ ,然后我们就可以枚举余数, 用该余数所代表的前缀和构成一个个区间和,
    这个题也就转化为了, 从一个余数相同的集合里面拿出两个数来,相减构成一个新的数,有多少方案 , 第一有num[i] 个方案 , 第二次有num[i - 1] 个方案, 但是有重复的,所以就是num[i] * (num[i ] - 1) / 2, 注意,num表示的是前缀和%k的余数, 我们用两个这种数来构造,是构造一个区间和满足题目要求, 但是这个区间和要是就是一个前缀和, 我们之前在一个集合里拿出两个元素的方法就不适用了, 因为那个是两个数相减, 要是只是前缀和%k == 0 了, 也就是前缀和就满足要求了,此时此刻,就是ans + num[0] 了

    #include <iostream>
    using namespace std;
    const int N = 5e5 +10 ;
    typedef long long ll ;
    ll a[N] ;
     
    int main()
    {
        int n , k ;
        cin >> n >> k ;
        ll t , sum = 0 ;
        for(int i = 1 ; i <= n ;i ++)
            cin >> t , sum += t , a[sum % k] ++ , sum %= k ;
        ll ans = 0 ;
         
        for(int i = 0 ;i <= k;i ++)
         ans += a[i] * (a[i] - 1) / 2 ;
        ans += a[0] ;
        cout << ans << endl ; 
        return 0 ;
    }
    
    每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
  • 相关阅读:
    poj 2485 Highways 最小生成树
    hdu 3415 Max Sum of MaxKsubsequence
    poj 3026 Borg Maze
    poj 2823 Sliding Window 单调队列
    poj 1258 AgriNet
    hdu 1045 Fire Net (二分图匹配)
    poj 1789 Truck History MST(最小生成树)
    fafu 1181 割点
    减肥瘦身健康秘方
    人生的问题
  • 原文地址:https://www.cnblogs.com/spnooyseed/p/12870885.html
Copyright © 2011-2022 走看看