小朋友的球
题目描述
@发源于 小朋友最近特别喜欢球。有一天他脑子抽了,从口袋里拿出了 N N N 个不同的球,想把它们放到 M M M 个相同的盒子里,并且要求每个盒子中至少要有一个球,他好奇有几种放法,于是尝试编程实现,但由于他天天不好好学习,只会上 B 站看游泳教练,于是他向你求助。
输入格式
多组数据,每行两个数 N , M N,M N,M。
输出格式
每组数据一行,表示方案数。
样例 #1
样例输入 #1
4 2
1 1
样例输出 #1
7
1
提示
- 对于 20 % 20\% 20% 的数据,满足 N , M ≤ 10 N,M \leq 10 N,M≤10;
- 对于 100 % 100\% 100% 的数据,满足 1 ≤ N , M ≤ 100 1 \leq N,M \leq 100 1≤N,M≤100,一个测试文件最多有 10 10 10 组测试数据。
思路
我们先设dp[i][j]
为i个不同的球,放在j个相同盒子中的方案数
对于第i个球
1.额外再放一个新的盒子中 dp[i-1][j-1]
2.放在已有的盒子中 dp[i-1][j]*j
我们不难得出状态转移方程,也就是dp[i][j]=dp[i-1][j-1]+dp[i-1][j]*j
50 P t s C o d e Pts Code PtsCode
我们使用__int128
,数据很有可能炸long long
,注意这里的__int128
的格式,前面有两个下划线。
__int128
的数据类型无法进行常规的输出,所以我们要手写一个
void write(__int128 x){
int ans[1005]={0},top=0;
do{
ans[top++]=x%10;
x/=10;
}while(x);
while(top){
putchar(ans[--top]+'0');
}
}
完整 C o d e Code Code
#include <iostream>
using namespace std;
const int N=105;
__int128 dp[N][N];
void write(__int128 x){
int ans[1005]={0},top=0;
do{
ans[top++]=x%10;
x/=10;
}while(x);
while(top){
putchar(ans[--top]+'0');
}
}
int main(){
int n,m;
for(int i=1;i<=100;i++){
for(int j=1;j<=100;j++){
if(j==1) dp[i][j]=1;
else dp[i][j]=dp[i-1][j-1]+dp[i-1][j]*j;
}
}
while(~scanf("%d%d",&n,&m)){
write(dp[n][m]);
printf("\n");
}
return 0;
}
我们这么写出来的代码无法拿到满分
A C AC AC 思路
我们观察数据,会发现有两个很大的数需要进行加法和乘法。
我们可以利用高精度去进行优化
加法:
node Add(node A,node B){
//高精度加法
node ans={0};
int len=max(A.len,B.len);
for(int i=1;i<=len;i++){
ans.num[i]+=A.num[i]+B.num[i];
if(ans.num[i]>=10){
ans.num[i+1]++;
ans.num[i]%=10;
if(i==len) len++;
}
}
ans.len=len;
return ans;
}
乘法:
node Mul(node A,int B){
//高精度乘法
int len=A.len;
node ans={0};
for(int i=1;i<=len;i++){
ans.num[i]+=A.num[i]*B;
ans.num[i+1]+=ans.num[i]/10;
ans.num[i]%=10;
}
while(ans.num[len+1]>0){
len++;
ans.num[len+1]=ans.num[len]/10;
ans.num[len]%=10;
}
ans.len=len;
return ans;
}
A C C o d e AC Code ACCode
#include <iostream>
using namespace std;
const int N=105;
struct node{
int num[1000];
int len;
};
node dp[N][N];
void write(node x){
for(int i=x.len;i>=1;i--){
putchar(x.num[i]+'0');
}
}
node Add(node A,node B){
//高精度加法
node ans={0};
int len=max(A.len,B.len);
for(int i=1;i<=len;i++){
ans.num[i]+=A.num[i]+B.num[i];
if(ans.num[i]>=10){
ans.num[i+1]++;
ans.num[i]%=10;
if(i==len) len++;
}
}
ans.len=len;
return ans;
}
node Mul(node A,int B){
//高精度乘法
int len=A.len;
node ans={0};
for(int i=1;i<=len;i++){
ans.num[i]+=A.num[i]*B;
ans.num[i+1]+=ans.num[i]/10;
ans.num[i]%=10;
}
while(ans.num[len+1]>0){
len++;
ans.num[len+1]=ans.num[len]/10;
ans.num[len]%=10;
}
ans.len=len;
return ans;
}
int main(){
int n,m;
for(int i=1;i<=100;i++){
for(int j=1;j<=100;j++){
if(j==1){
dp[i][j].len=1;
dp[i][j].num[1]=1;
}
else{
//dp[i][j]=dp[i-1][j-1]+dp[i-1][j]*j;
dp[i][j]=Add(dp[i-1][j-1],Mul(dp[i-1][j],j));
}
}
}
while(~scanf("%d%d",&n,&m)){
if(n<m) putchar('0');
write(dp[n][m]);
putchar('\n');
}
return 0;
}
AC咯!(喜)