332 · 恢复数组

小九有一个长为 nnn 的整型数组,数组中的每个数都在 lll 和 rrr 之间,而且数组的和是 333 的整数倍。
请帮小九计算出这个数组一共有多少种不同的可能。
输出要对 109+710^9+7109+7 取模

数组的长度为 nnn,满足 1≤n≤1051 \le n \le 10^51≤n≤105。
数组中的每个元素都满足,l≤ai≤r,1≤l≤r≤109l \le a_i \le r, 1 \le l \le r \le 10^9l≤ai​≤r,1≤l≤r≤109。
样例中,可能的数组有 [1,2],[2,1],[3,3][1,2], [2, 1], [3, 3][1,2],[2,1],[3,3]。

样例

 
输入:
n = 2
l = 1
r = 3
输出:
3

 

//
//重要信息:数组和是3的倍数,那么我们可以求出余数为0,1,2的组合数
//
//假设
//c0代表余数为0的组合数,c1代表余数为1的组合数,c2代表余数为2的组合数
//f0代表l - r余数为0的数量,f1代表l - r余数为1的数量,f2代表l - r余数为2的数量
//
//朴素的递推方式为:
//1:dp[i][c0] = dp[i - 1][c0] * f0 + dp[i - 1][c2] * f1 + dp[i - 1][c1] * f2
//2: dp[i][c1] = dp[i - 1][c1] * f0 + dp[i - 1][c0] * f1 + dp[i - 1][c2] * f2
//3 : dp[i][c2] = dp[i - 1][c2] * f0 + dp[i - 1][c1] * f1 + dp[i - 1][c0] * f2
//
//这里有个优化的小技巧,不用循环l - r的每个数字算f0, f1, f2,那样会超时,现在直接利用数量除以3算数量即可,详见代码

int restoreArray(int n, int l, int r) {
    // write your code here.
    int mod = 1000000000 + 7;
    uint64_t f[3] = {0,0,0};
    int v = l;
    for (; v <= r && v % 3 != 1; v++)
    {
        f[v % 3]++;
    }
    int t = (r - v + 1) / 3;
    int e = (r - v + 1) % 3;
    f[0] += t;
    f[1] += t;
    f[2] += t;
    if (e >= 1) {
        f[1]++;
    }
    if (e > 1) {
        f[2]++;
    }
    uint64_t c[3] ;
    c[0] = f[0];
    c[1] = f[1];
    c[2] = f[2];
    uint64_t t0;
    uint64_t t1;
    uint64_t t2;
    for (int i = 1; i < n; i++)
    {
        t0 = c[0];
        t1 = c[1];
        t2 = c[2];
        c[0] = (f[0] * t0 + f[1] * t2 + f[2] * t1) % mod;
        c[1] = (f[0] * t1 + f[1] * t0 + f[2] * t2) % mod;
        c[2] = (f[0] * t2 + f[1] * t1 + f[2] * t0) % mod;
    }
    return (int)c[0];
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值