三个袋子

(文章修改于2020年3月22日23点45分)
第二次做这个原题时WA了两次,才发现是有些隐蔽的数据不能通过(如32532525 99999)为防止溢出,将所有的int型改为long long int型
时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
平平在公园里游玩时捡到了很多小球,而且每个球都不一样。平平找遍了全身只发现了3个一模一样的袋子。他打算把这些小球都装进袋子里(袋子可以为空)。他想知道他总共有多少种放法。
将N个不同的球放到3个相同的袋子里,求放球的方案总数M。
结果可能很大,我们仅要求输出M mod K的结果。
现在,平平已经统计出了N<=10的所有情况。见下表:

N12345678910
M1251441122365109432819842

输入
两个整数N,K,N表示球的个数。
输出
输出仅包括一行,一个整数M mod K 。
样例输入 Copy

11 10000

样例输出 Copy

9525

提示
对于 40%数据,10<=N<=10,000
对于100%数据,10<=N<=1,000,000,000
对于 100%数据,K<=100,000
方法一:
题目给出了1~10的结果,那我们就充分利用这10个结果。我们让后一个数减前一个数,通过归纳猜想可以发现相邻两个数的差是3的整数次幂,而且随着n的增大,在不取模的前提下这种关系肯定成立,因此构造递推关系:n=1时,f(1)=1;n>=2时,f(n)-f(n-1)=3^(n-2),利用累加法求得通项为f(n)=(3^(n-1)+1)/2。经检验通项公式符合题意。
方法二:
直接推导:假设3个盒子都不相同,则每个球都有3种选择,n个球有3^n次种,实际上需要除去重复的部分,即除以3!,而当有两个袋子为空时,只算了三种情况,需要补足,因此答案为(3^n+3)/6,即(3^(n-1)+1)/2
得到通项公式后,接下来就求(3^(n-1)+1)/2对K取模。实际操作发现,如果直接运用模的运算法则计算的话,过程较麻烦,而且答案也不对,搞了好久才发现是1/2的问题。现令(3^(n-1)+1)/2=x*k+t,这里的t是取模后的结果。一般地,有(a/b)mod c=(a mod (bc))/b,这样的目的是消除分式对取模的影响。转化一下就得到3^(n-1)+1=2*x*k+2*tt=((3^(n-1)+1)%(2*k))/2=((3^(n-1)%(2*k)+1)%(2*k))/2,这里的1%(2*k)直接写成1,3^(n-1)%(2*k)部分就是典型的快速幂算法。

#include<stdio.h>
typedef long long int lli;//为防止溢出,将所有的int型改为long long int型
lli quick_pow(lli b,lli mod)//快速幂
{
    lli a=3;
    lli ans=1;
    mod=mod*2;
    while(b)
    {
        if(b%2==1)
        {
            ans=ans*a%mod;
        }
        a=a*a%mod;
        b=b/2;
    }
    return ans;
}
int main()
{
    lli n;
    lli k;
    scanf("%lld %lld",&n,&k);
    printf("%lld",(quick_pow(n-1,k)+1)%(2*k)/2);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值