牛客21738 牛牛与数组

21738 牛牛与数组

#include <iostream>

using namespace std;

/*1:长度为n
**2:每一个数都在1到k之间
**3:对于任意连续的两个数A,B,A<=B 与(A % B != 0) 两个条件至少成立一个
**请问一共有多少满足条件的数组,对1e9+7取模
**1 ≤ n ≤ 10     1 ≤ k ≤ 100000*/
/**任意连续指的是啥 “A B连续” - A B?**/

typedef long long ll;
const int mod = 1e9 + 7;
int dp[11][100001];//用dp[i][j]记录结果,表示在第i位放j的方案数

int main()
{
    int n = 0, k = 0;
    ll ans = 0, sum = 0, sum1 = 0;

    cin >> n >> k;

    //按位处理 先处理1位
    for(int i = 0;i <= k;i++)
    {
        dp[1][i] = 1; //均只有1种情况
    }

    //处理2位+
    for(int i = 2;i <= n;i++) //1位已经过处理 从第二位向后
    {
        sum = 0;

        //符合条件太难找 最好找不符合条件的
        //全部可能情况
        for(int j = 1;j <= k;j++)
        {
            sum += dp[i - 1][j]; //全部情况 也就是全都选 上一位多少方案数就是多少
            /**correct 记得随时取余**/
            sum %= mod;
        }

        //不符合条件的情况
        for(int j = 1;j <= k;j++)
        {
            sum1 = 0;
            //A<=B 与(A % B != 0)
            //要么小于 要么不是倍数
            //所以不符合的条件即为: 大于且是倍数
            for(int z = j + j;z <= k;z += j)
            {
                sum1 += dp[i - 1][z];
                sum1 %= mod;
            }

            /**初 不知道在哪里统计答案**/
            dp[i][j] = (sum - sum1) % mod;
        }
    }

    /**初 如何统计最终答案 不是写二重循环!**/
    for(int j = 1;j <= k;j++)
    {
        ans += dp[n][j];
        ans %= mod; //不要忘记取余z
    }

    cout << ans << endl;
    return 0;
}

dp的核心是要找到状态转移方程,也就是要把问题归纳为相似步骤的不断重复(在这个过程中产生种种状态)。在具体解决的时候,就是找到当前状态与上一状态(或下一状态)的关系(表达式)。
本问题中可以把找数组种类的过程看成在手动生成数组,是从第一位到第n位逐一选择,完成全过程后便得到了可能的数组。dp[i][j]的表达可能不太好想,我看了题解才想到。用i来标记第i位,用j表示当前位选择j的所有可能方案数。
状态转移的过程其实就是在i-1的基础上,挑选可行的j(从1-k题给范围选)放在第i位上。因为条件是或,会比较复杂,如果我们从反面考虑会简单一些。那么当前方案数就是 全部方案 - 不可行方案,这里要注意全部方案其实就是所有的j都选入,也就是dp[i - 1][j]!**还有一点待解决的问题就是为什么从0开始计数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值