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 ;
    }
    
    每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
  • 相关阅读:
    innerHTML使用方法
    HDU 1426 Sudoku Killer
    Junit使用教程(一)
    HLS协议实现
    GPIO
    TraceView总结
    在kettle中实现数据验证和检查
    用户向导左右滑动页面实现之ImageSwitcher
    DWZ使用笔记
    oracle进程
  • 原文地址:https://www.cnblogs.com/spnooyseed/p/12870885.html
Copyright © 2011-2022 走看看