CF2091G dp *2300

\[\begin{flalign*} &题意:给定s和k,起点0,初始向右,步长k,每次转向步长变为max(1,k-1)\\& 问恰好到达s时最大步长&\\& 显然s>=k^2时必然有解,max(k-2,1)\\& 初始会剩下s\ mod \ k的长度,然后转向,相当于模意义上的加1,由于上一次能走k步\\& 那么必然能取完剩余系让余数被k-2整除\\& 剩下来的是s\le 1e6的时候该如何求解,考虑dp\\& dp_{i,k}代表步长为i的时候是否能到达k\\& 可以考虑调和级数枚举+可变长bitset优化dp做到O(SklogS/64)\\& 或者直接倒序枚举进行dp,转移为:\\& dp[i][j]=dp[i][j-i]|dp[i+1][j-i] \end{flalign*} \]

#include<tr2/dynamic_bitset>
using std::tr2::dynamic_bitset;
void solve(){
	int s;
	cin>>s>>k;
	if(s>=k*k){
		if(s%k==0) cout<<k<<endl;
		else cout<<max(1ll,k-2)<<endl; return;
	}
	vector<dynamic_bitset<>>dp(k+1);
	for(int i=0;i<=k;i++) dp[i].resize(s+1);
	for(int j=0;j<=s;j+=k) dp[k][j]=1;
	for(int i=k-1,cnt=0;i>=1;i--,cnt++){
		if(dp[i+1][s]) return cout<<i+1<<endl,void();
		if(cnt&1)
			for(int j=0;j<=s;j+=i){
				dp[i]|=(dp[i+1]<<=i);
			}
		else 
			for(int j=s;j>=0;j-=i){
				dp[i]|=(dp[i+1]>>=i);
			}
	}
	cout<<1<<endl;
}
posted @ 2025-04-03 13:39  肆惠  阅读(13)  评论(0)    收藏  举报