zoukankan      html  css  js  c++  java
  • Codeforces Round #533 C. Ayoub and Lost Array

    题面:

    传送门 

    题目描述:

    题意很简单:1.数组中的所有整数都在区间[l, r],2.所有元素之和能被3整除。现在知道这个数组的大小,l和r,问:按照题目的要求组成的数组一共有多少种可能。
     

    题目分析:

    这道题应该是一道常见的用dp来解决计数的问题。
    1.如果忽略所有元素之和能被3整除,那么,按照正常的想法答案肯定是:(r-l+1)n。但是题目多了所有元素之和能被3整除,看似难度大了很多。其实,我们可以分析一下:忽略所有元素之和能被3整除,答案是怎样想出来的:每一个“位”上都有(r-l+1)种选择,然后把每个“位”上的选择乘起来,就是(r-l+1)n。因此,我们可以通过研究每个"位"上的选择来解决这个问题。但在实际情况中,这个“位”的选择实在是不好解决:要确定所有元素之和要被3整除,有些“位”可能是之前不能被3整除,经过几次累加后就能被3整除了,情况过于复杂。这时,我们要想一种能“简化过程”的思想:
    把问题拆解子问题,对应的解决办法其中就有dp。我们可以这样定义问题:前n个数的和能被3模余p(p = 0, 1, 2)的可能有多少?那么其中一个子问题是:前n-1个数的和能被3模余p(p = 0, 1, 2)的可能有多少?换成更直观的图,其实就是:
    前n-1位已经确定好(计算出前n-1位的可能数),如果确定了第n位的选择,那么根据组合数学计数原理,就可以用前n-1位计算出的结果计算出前n位一共有多少种选择。第n位的选择要看当前的“状态”是什么:也就是和p有关。
     
    2.经过分析,有如下选择(这里用dp[p][n]来代表上面的含义):
    当p == 0时:
    dp[0][n] += dp[0][n-1] * (第n位选被3模后余数为0的数的个数)
    dp[0][n] += dp[1][n-1] * (第n位选被3模后余数为2的数的个数)
    dp[0][n] += dp[2][n-1] * (第n位选被3模后余数为1的数的个数)
     
    当p == 1时:
    dp[0][n] += dp[0][n-1] * (第n位选被3模后余数为1的数的个数)
    dp[0][n] += dp[1][n-1] * (第n位选被3模后余数为0的数的个数)
    dp[0][n] += dp[2][n-1] * (第n位选被3模后余数为2的数的个数)
     
    当p == 2时:
    dp[0][n] += dp[0][n-1] * (第n位选被3模后余数为2的数的个数)
    dp[0][n] += dp[1][n-1] * (第n位选被3模后余数为1的数的个数)
    dp[0][n] += dp[2][n-1] * (第n位选被3模后余数为0的数的个数)
    我们先看看当p == 0时,是怎样得到结果的:有三种情况:第一种情况:前n-1个数的和取模后余数为0且第n个数选余数为0的数,这样才能保证前n位之和取模后余数为0(也就是p);第二种情况:前n-1个数的和取模后余数为1且第n个数选余数为2的数,这样才能保证前n位之和取模后余数为0(也就是p);第三种情况同理可得,p == 1和p == 2也同理可得。
     
    3.现在的问题关键是:第n位选被3模后余数为p的数的个数怎么算:我们可以思考这样一个问题:1-x中,被3取模后余数为p的数的个数 fp(x) 是多少?假如我们解决这个问题,就可以用 fp(r) - fp(l-1) 来算出答案了。因为p的选择不多(p = 0, 1, 2),所以我们直接分类讨论就行了:
    1-x中,被3取模后余数为0的数的个数:f0(x) = x / 3
    1-x中,被3取模后余数为1的数的个数:f1(x) = (x + 2) / 3
    1-x中,被3取模后余数为2的数的个数:f2(x) = (x + 1) / 3
     
    4.自己注意初始化问题。
     
     
    AC代码:
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <cmath>
     5 #include <algorithm>
     6 using namespace std;
     7 const long long mod = 1e9+7;
     8 const long long maxn = 2e5+5;
     9 long long n, l, r;
    10 
    11 long long dp[5][maxn];
    12 
    13 const int yu[3][3] = {{0, 2, 1}, {1, 0, 2}, {2, 1, 0}};
    14 
    15 
    16 int main(){
    17     cin >> n >> l >> r;
    18     int t;
    19     
    20     //注意初始化 
    21     for(int i = 0; i < 3; i++){
    22         t = (3-i)%3;
    23         dp[i][1] = ( (r+t)/3-(l+t-1)/3 );
    24     }
    25     
    26      
    27     for(int i = 2; i <= n; i++){
    28         for(int k = 0; k < 3; k++){
    29             for(int p = 0; p < 3; p++){
    30                 t = (3-yu[k][p]) % 3;
    31                 dp[k][i] += dp[p][i-1]*( (r+t)/3-(l+t-1)/3 ) % mod;
    32                 dp[k][i] %= mod;
    33             }
    34         }
    35     }
    36     
    37     cout << dp[0][n] << endl;
    38     
    39     return 0;
    40 }
     
     
     
     
  • 相关阅读:
    【Life】 今天的思考
    【openpyxl】 关于 单元格背景色 的疑惑
    【xlwings】 wps 和 office 的excel creat_sheet区别
    [git] git error: unable to unlink old
    【python tkinter】对于窗口存在的认识
    【求教 探讨】python tkinter的messagebox
    [python]近日 用3种库 实现简单的窗口 的回顾~
    AE(After Effects)的简单使用——记一次模板套用的过程
    python3爬虫应用--爬取网易云音乐(两种办法)
    【KataDaily 191015】Sort the Gift Code
  • 原文地址:https://www.cnblogs.com/happy-MEdge/p/10640811.html
Copyright © 2011-2022 走看看