2025春季杭电多校5题解
1009
这么能猜?
这个数据范围,对博弈论来说一定存在某种结论。故这题是结论题。
设\(dp[n]\)表示有\(n\)个物体时敌方先手,我的胜率。则敌方先手后轮到我时有n-1或者n-4个物体,我再取物体。我取物体时肯定要的是胜率最大,所以有转移方程\(dp[n]=\frac{1}{2}*max(dp[n-1-1],dp[n-1-4])+\frac{1}{2}*max(dp[n-4-1],dp[n-4-4]))=\frac{max(dp[n-2],dp[n-5])+max(dp[n-5],dp[n-8])}{2}\)。数组越界时说明不存在这种选取方案。可以根据这个递推式打表或者手搓20以内的结果,就能发现规律。
赛时还是不够冷静啊!!!,可惜了,代码如下:
const int mod=998244353;
int ksm(int x,int y){
int ans=1,base=x;
while(y){
if(y&1){
ans*=base;
ans%=mod;
}
base*=base;
base%=mod;
y>>=1;
}
return ans%mod;
}
int inv(int x){
return ksm(x,mod-2)%mod;
}
void solve(){
int n;
cin>>n;
int m=n%5,a,b;//a分母,b分子
if(m==2||m==0){
cout<<1<<endl;
return;
}else if(m==1){
if(n==1) a=2,b=1;
else a=ksm(2,n/5),b=a-1;
}else if(m==3){
if(n==3) a=4,b=3;
else a=ksm(2,ceil(n/5.0)+1),b=a-1;
}else if(m==4){
if(n==4) a=2,b=1;
else a=ksm(2,ceil(n/5.0)),b=a-1;
}
cout<<(b%mod*inv(a)%mod)%mod<<endl;
}
等整理完最近的学习笔记,再来追更1004和1003
耽搁了好久,过来更新了。
1004
这个题的第一眼我的想法是多重背包,可以对余数分类,然后可以求出每个余数类有多少个,那么这个题就相当于从每个类中取若干个,然后求和,要求最后的和模m为0,求方案数。看一眼数据范围,嗯,写不了。多重背包有一维是每种物品的方案数,所以这么想肯定不行。
经过后来的学习,了解到生成函数也可以求方案数,现在讲解这种方法。
我们对每个余数分类后,对某一余数类中的某一个数,都有两种状态,选或者不选,假设这个数为\(a\),那么就有生成函数\(x^{0*a}+x^{1*a}\),要取模的话,就是\(1+x^{r}\),而有\(cnt[r]\)个这样的数,那么这个余数类\(r\)能够形成的方案数的生成函数就是\((1+x^r)^{cnt[r]}\)。在这个多项式中\(x\)并无实际意义,\(x\)的指数是每种方案取出来的数的和,而\(x\)的系数就是对应的方案数。事实上这个就是\(01\)背包的生成函数,所以也能看到有大神用\(01\)背包做。我们将每一个余数类的多项式乘在一起,\((1+x^0)^{cnt[0]}*(1+x^1)^{cnt[0]}……*(1+x^{m-1})^{cnt[m-1]}\)。这个多项式展开后,系数,指数所代表的意义依然不变,这也就是说,所有指数为\(m\)的倍数的项的系数之和,就是我们要求的答案。更进一步,如果我们在处理多项式的时候就对指数的运算进行取模,那么所有指数为\(m\)倍数的项取模后都会变成\(0\),这也就意味着最后的答案是取模处理后多项式中指数为\(0\)的项的系数\(-1\),\(-1\)是因为取模处理前的多项式含有指数为\(0\)的项,而0本身不算作\(m\)的倍数(准确的说不是我们要的和),所以取模后要把原本包含的这个减掉,而指数为\(0\)意味着和为\(0\),那就是一个数都不选,方案数为\(1\),所以要减\(1\),这也是部分大佬代码中\(ans[0]-1\)的由来。
所以,问题本身就变成了求多项式的系数。
代码方面\((1+x^r)^{cnt[r]}\),多项式快速幂即可。每个余数类的多项式相乘,卷积即可。时间复杂度\(O(能过)\)
#define int long long
const int mod=998244353;
std::vector<int> mul(std::vector<int>&a,std::vector<int>&b,int m){
std::vector<int>ans(m,0);
for(int i=0;i<a.size();i++){
for(int j=0;j<b.size();j++){
ans[(i+j)%m]=(ans[(i+j)%m]%mod+(a[i]%mod*b[j]%mod))%mod;
}
}
return ans;
}
std::vector<int> pksm(std::vector<int>&a,int b,int m){
std::vector<int>ans(m,0); ans[0]=1;
std::vector<int>base=a;
while(b){
if(b&1)ans=mul(ans,base,m);
base=mul(base,base,m);
b>>=1;
}
return ans;
}
void solve(){
int n,m;
std::cin>>n>>m;
std::vector<int>cnt(m,0);
for(int r=0;r<m;r++){
if(r>n) cnt[r]=0;
else if(!r) cnt[r]=n/m;
else cnt[r]=(n-r)/m+1;
}
std::vector<int>ans(m,0);
ans[0]=1;
for(int r=0;r<m;r++){
if(!cnt[r]) continue;
std::vector<int>a(m,0);
if(!r) a[0]=2;
else a[0]=1,a[r]=1;
a=pksm(a,cnt[r],m);
ans=mul(a,ans,m);
}
std::cout<<(ans[0]-1+mod)%mod<<'\n';
}

浙公网安备 33010602011771号