妞妞的三个盒子
题目描述:
妞妞在公园里游玩时捡到了很多小球,而且每个球都不一样。妞妞找遍了全身只发现了3个一样的盒子。她打算把这些小球都装进盒子里(盒子可以为空)。她想知道她总共有多少种放法。
将N个不同的球放到3个相同的盒子里,求放球的方案总数M。 结果可能很大,我们仅要求输出M mod K的结果。 现在,妞妞已经统计出了N<=10的所有情况。见下表:
N | M |
---|---|
1 | 1 |
2 | 2 |
3 | 5 |
4 | 14 |
5 | 41 |
6 | 122 |
7 | 365 |
8 | 1094 |
9 | 3284 |
10 | 9842 |
输入格式:
两个整数 N,K 表示球的个数。
输出格式:
输出仅包括一行,一个整数 M mod K 。
输入样例:
11 10000
输出样例:
9525
数据范围与提示:
对于40%数据,10<=N<=10,000;对于100%数据,10<=N<=1,000,000,000;
对于 100%数据,K<=100,000。
题解:
看表格是否看到想哭
其实这题可能很多人都可以很快的发现一个规律
当前这个数等于前面那个数
×
\times
× 3
−
-
− 1
应该也许都看出来了吧
其实大家再把表格里的数都乘
2
2
2 看看
跟
2
2
2 的几次方是否有点关系
与
3
3
3 的几次方哈
其实应该都发现了每个对应的 M M M 都是 ( 3 n − 1 + 1 ) ÷ 2 (3^{n-1}+1)\div2 (3n−1+1)÷2
然后就可以了呀用个快速幂就搞定了
因为有 ÷ 2 \div\ 2 ÷ 2
所以要用逆元
也可以不用逆元把模数乘 2 2 2 即可
来解释一下
有点复杂不解释了
上代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
LL ksm(LL a,int b,int m)
{
LL ans=1;
while(b)
{
if(b&1)ans=ans*a%m;
a=a*a%m;
b>>=1;
}
return ans;
}
int main()
{
freopen("bags.in","r",stdin);
freopen("bags.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
m<<=1;//这里就是乘2,左移应该也许看的懂吧
printf("%lld",((ksm(3,n-1,m)+1)/2)%m);
return 0;
}