题解:P17301 [ICPC 2026 Xi'an I] Unreachable Land
lailai0916 · · 题解
题意简述
初值为
解题思路
先研究当前值已经小于
当前值已经等于目标时,不再执行任何取模便得到唯一方案,所以
对于
执行
此后从
处理到模数
每个合法方案都有唯一的第一次执行取模的位置,
而每个转移项都完整枚举了取模后不改变数值的选择,
再接上由
原问题从
最后一式只需枚举一次。
瓶颈在于计算
令:
再令
对
固定:
产生同一个
令
所以每个转移项可以拆成:
对每一对
求和范围是当前区间已经覆盖到的所有
还需说明这个前缀和可以增量维护。
对固定的
在 lst 记录当前端点。
因为
可用的
所以空间复杂度为
参考代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=200005;
const int M=400005;
const int K=450;
const int mod=998244353;
const int inv2=499122177;
int f[N],pw[M],ip[M],g[K][K],lst[K][K];
int solve(int a,int b,int m)
{
fill(f,f+m,0);
f[b]=1;
int s=(int)sqrt(m);
int c=max(b+1,s+1);
int q=(m-1)/c;
for(int i=1;i<=q;i++)
{
fill(g[i],g[i]+i,0);
fill(lst[i],lst[i]+i,-1);
}
for(int i=b+1;i<m;i++)
{
ll res=0;
for(int j=b+1;j<=min(s,i);j++)
{
int r=i%j;
res+=(ll)f[r]*pw[j-r-1]%mod;
}
for(int k=1;k<=i/c;k++)
{
int l=max(c,i/(k+1)+1);
int y=i-k*l;
int r=i%k;
if(lst[k][r]<y)
{
g[k][r]=int((g[k][r]+(ll)f[y]*ip[y+y/k])%mod);
lst[k][r]=y;
}
res+=(ll)g[k][r]*pw[i/k-1]%mod;
}
f[i]=int(res%mod);
}
ll ans=0;
for(int j=b+1;j<=m;j++)
{
int r=a%j;
ans+=(ll)f[r]*pw[j-r-1]%mod;
}
return int(ans%mod);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
pw[0]=1;
ip[0]=1;
for(int i=1;i<M;i++)
{
pw[i]=int((ll)pw[i-1]*2%mod);
ip[i]=int((ll)ip[i-1]*inv2%mod);
}
int T;
cin>>T;
while(T--)
{
int a,b,m;
cin>>a>>b>>m;
cout<<solve(a,b,m)<<'\n';
}
return 0;
}