P7481 梦现时刻 题解 (洛谷4月月赛 D)
题目大意:给定正整数
看似是一道数学题,但是我们可以将它“实际化”来做。
我们可以将
于是,
我们现设
这样我们就把一道数学问题转化成了一道动态规划问题。
为了方便,我们再设
得出递推式:
-
f(i,j)=f(i-1,j)+g(i-1,j) 其中
f(i-1,j) 表示第一步不取第i 个球(第二步仍然可以取),g(i-1,j) 表示第一步取第i 个球(第二步就不能取了)。 -
g(i,j)=f(i,j)-g(i,j-1) 其中
f(i,j) 代表第二步取不取第i+1 个球无所谓,g(i,j-1) 代表第二步取第i+1 个球(于是只能从剩下的球中取出j-1 个,且不能取第i+1 个球)。
边界条件:
原来的
至于
算法时间复杂度为 (究竟赛时没有做出来)
附上代码:
#include <bits/stdc++.h>
#define For(i,a,b) for(int i=a;i<=b;i++)
#define Rev(i,a,b) for(int i=a;i>=b;i--)
#define clr(a,val) memset(a,val,sizeof(a))
#define int long long
using namespace std;
// f(i,j)=g(i-1,j)+f(i-1,j)
// g(i,j)=f(i,j)-g(i,j-1)
// f(0,i)=C(n,i)
// f(i,0)=2^n
// g(0,i)=C(n-1,i)
// g(i,0)=2^n
const int N=5e3+5,mod=998244353;
int n,m,f[N][N],g[N][N];
int inv[N];
int qpow(int x,int y)
{
int res=1;
while(y){
if(y&1ll) res=res*x%mod;
x=x*x%mod;
y>>=1ll;
}
return res;
}
signed main()
{
cin>>n>>m;
inv[0]=1;
For(i,1,m){
inv[i]=qpow(i,mod-2);
}
f[0][0]=1;
For(i,1,m){
f[0][i]=f[0][i-1]*(n-i+1)%mod*inv[i]%mod;
f[i][0]=f[i-1][0]*2%mod;
}
g[0][0]=1;
For(i,1,m){
g[0][i]=g[0][i-1]*(n-i)%mod*inv[i]%mod;
g[i][0]=g[i-1][0]*2%mod;
}
int ans=0;
For(i,1,m){
For(j,1,m){
f[i][j]=(g[i-1][j]+f[i-1][j])%mod;
g[i][j]=((f[i][j]-g[i][j-1])%mod+mod)%mod;
ans^=f[i][j];
}
}
cout<<ans<<endl;
return 0;
}
另:这是本人的第一篇题解,若有不到之处望大家多多包涵:)