青青草原的表彰大会 NOIP多校

这个题非常好,尤其是其正解的思路转换方式,真的特别需要整理一下。

首先,k个羊,n种钱,构造序列为前一个是后一个数的因子,不难想到记录长度,因为长度为i+1的可以由长度为i的转移过去,朴素可以想到dp【i】【j】代表长度为i,末尾为j的方案数,那么转移就是f[i+1][j]=d|j  dp[i][d] 新加入的这个数是j的因子。这样时间复杂度根本不行,所以我们大胆的将一个数拆为log级别,怎么想呢,末尾数必须要记录,将一维定为长度已经为k,k里面不同的个数有多少个,因为每次都是倍数关系,这个数量级就是log的了,所以dp【i】【j】代表k个羊中的方案数,最后咱们将同种的所有dp数求和,在k个羊中有i中不同的方式,就是隔板法cnm了,而且状态转移也很明显,dp【i+1】k从1到n/j【j*k】+=dp[i][j],也就是咱们最开始的那种思路的一种转换

 

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxx=1e6+5;
ll n,i,j,k,t,cnt=0;
const ll mod=1e9+7;
ll dp[23][maxx]={0};
 
ll sum[maxx]={0};
ll jiecheng[maxx];
ll niyuan(ll a,ll b) // 阶乘逆元求解。
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=(ans*a)%mod;
        a=a*a%mod;
        b/=2;
    }
    return ans;
}
ll c(ll a,ll b)
{
    ll x=niyuan(jiecheng[b],mod-2)*niyuan(jiecheng[a-b],mod-2)%mod;
    return (jiecheng[a]*x)%mod;
}
int main()
{
    ll l,r,p;
    jiecheng[0]=1;
    jiecheng[1]=1;
    for(i=2;i<maxx;i++) jiecheng[i]=(i*jiecheng[i-1])%mod;
    cin>>n>>k;
    //cnt=log2(n)+1;
    //printf("%lld\n",cnt);
    //printf("%lld\n",jiecheng[6]);
    for(i=1;i<=n;i++) dp[1][i]=1;  // 不同种为1的全是一种
 
    for(i=1;i<21;i++)  // log2(n)的最大值
    {
        for(j=1;j<=n;j++)
        {
            for(p=j+j;p<=n;p+=j)
            {
                dp[i+1][p]+=dp[i][j];// 状态转移
                dp[i+1][p]%=mod;
            }
        }
    }
    for(i=1;i<21;i++)
    for(j=1;j<=n;j++)
    {
        sum[i]+=dp[i][j]; sum[i]%=mod;  // 将不同种数的和加起来。
    }
    ll ans=0;
    for(i=1;i<=n&&i<21;i++)
    {
        ans=(ans+sum[i]*c(k-1,i-1))%mod;  // 在k个中不同的i种的方案数的求和。
    }
    //for(i=1;i<=n;i++) printf("%lld\n",sum[i]);
    printf("%lld\n",ans);
    return 0;
}


青青草原上有k只羊,他们聚集在包包大人的家里,举办一年一度的表彰大会,在这次的表彰大会中,包包大人让羊们按自己的贡献从小到大排成一排,以便于发放奖金。每只羊都会得到数值在1~n的奖金,并且第i只羊的奖金应为第i+1只羊的约数(即满足ai|ai+1)。现在包包大人想知道一共有多少种不同的发放奖金的方式(两种发放奖金的方式不同是指在两种发放奖金的方式中存在

某只羊拿到的奖金不同)

输入

一行两个正整数n,k,满足(1<=n,k<=1000000)

输出

一行一个整数代表发放奖金的方案对1000000007取模的结果

样例输入 Copy

6 4

样例输出 Copy

39

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值