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';
}
posted @ 2025-09-11 18:04  CyansQwQ  阅读(12)  评论(0)    收藏  举报