2026.8.13
A
给定正整数 \(n,k\),求将 \(n\) 个相同弹珠划分到 \(k\) 个相同盒子且每个盒子非空的方案数,答案对 \(998244353\) 取模。数据范围:\(1 \le k \le n \le 5000\)。
似乎是一个经典的 DP 但是我好像真没见过。
考虑 \(dp(i,j)\) 表示 \(i\) 个数分到 \(j\) 个盒子的方案数。因为必须要保证数列的非增(非降)性,保证不重复,所以可以考虑以下两种操作:一种是在最前面加一个 \(1\),一种是所有数都 \(+1\)。
- 至少有一个是 \(1\),那就把这个 \(1\) 拿走,剩下 \(i-1\) 个分成 \(j-1\) 组(相当于在前面补 \(1\))
- 没有一个 \(1\),那就全体 \(-1\),剩下 \(i-j\) 个分成 \(j\) 组(相当于集体 \(+1\))
然后状态转移:
发现如果用插板法直接 \(\binom{n-1}{k-1}\) 的话,会有重复的,而且每种组合的重复数还不一样(比如 \((1,1,2)\) 有三种,而 \((1,1,1)\) 只有一种),所以不能这样,然后赛时只会这样然后又光荣爆 T1 了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
constexpr int N=5007;
constexpr int mod=998244353;
int n,k;
ll dp[N][N];
int main()
{
// freopen("neuvillette.in","r",stdin);
// freopen("neuvillette.out","w",stdout);
cin.tie(0)->sync_with_stdio(0);
cin>>n>>k;
dp[0][0]=1; dp[1][1]=1;
for(int i=2;i<=n;i++)
for(int j=1;j<=i;j++) dp[i][j]=(dp[i-1][j-1]+dp[i-j][j])%mod;
cout<<dp[n][k]%mod;
cout.flush();
return 0;
}
/*
dp[i][j]表示i个苹果放进j个盘子的方案数
至少有一个是1,那就把这个1拿走,剩下i-1个分成j-1组(相当于在前面补1)
没有一个1,那就全体-1,剩下i-j个分成j组(相当于集体+1)
dp[i][j]=dp[i-1][j-1]+dp[i-j][j]
*/
B
给定正整数 \(N,K\),求将 \(N\) 个不同的球放入 \(3\) 个相同袋子(袋子允许为空)的方案数 \(M\),输出 \(M \bmod K\)。数据范围:\(10 \le N \le 10^9,K \le 10^5\)。
题目居然把 \(n=1 \sim 10\) 都打好了,这不是直接猜结论?
使用 Desmos 描点,然后使用高一必修一学过的函数拟合方法猜。首先发现是指数级增长,所以直接猜一个指数型函数;然后又是 \(3\) 个袋子,所以是 \(3^x\),然后不断调参,发现是 \(\dfrac12 (3^x-1)\) 然后发现点似乎集体偏移了,然后变成 $\dfrac{1}{2} \left(3^{x-1}+1\right) $ 就直接过了。
怎么处理这个傻逼任意模数?首先答案 \(A=\dfrac{1}{2} \left(3^{x-1}+1\right)\) 是偶数,然后有关系式:
设 \(A = 2k \cdot q + r\),其中余数 \(r\) 满足 \(0 \leq r < 2k\)。因为 \(2k\) 是偶数,且 \(A\) 是偶数,所以余数 \(r\) 也必然是偶数。令 \(r = 2t\)。则 \(A / 2 = k \cdot q + t\)。因此 \((A / 2) \bmod k = t\)。而代码右边 \((A \bmod 2k) / 2 = r / 2 = t\)。两边相等,定理得证。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
constexpr int N=-1;
ll mod;
ll ksm(ll a,ll b)
{
ll s=1;
while(b)
{
if(b&1) s=s*a%mod;
a=a*a%mod;
b>>=1;
}
return s;
}
int main()
{
// freopen("neuvillette.in","r",stdin);
// freopen("neuvillette.out","w",stdout);
cin.tie(0)->sync_with_stdio(0);
ll n;
cin>>n>>mod; mod*=2;
ll tmp=(ksm(3,n-1)%mod+1);
cout<<tmp/2;
cout.flush();
return 0;
}
/*
使用desmos拟合可知解析式为\frac{1}{2}\left(3^{\left(x-1\right)}+1\right)
2在任意模数下的逆元?
A mod m=r
(2A) mod (2m)=2r
(2a) mod 2m=2(a mod m)
a mod m=1/2 (a mod 2m)
*/

浙公网安备 33010602011771号