「杂题乱刷2」P11267
题目链接
解题思路
先考虑对于
那么为什么只用处理
我们可以发现,由于字符串是无线循环的,所以对于位置模
我们可以先将字符串断环成链倍长后做前缀和来处理
然后容易二分得出往后跳的距离。
然后我们就可以求出对于每个点
然后问题询问的是往后跳
这是一个经典的倍增问题,直接倍增即可。
注意,在倍增过程中,可能答案会爆 long long
。
参考代码
记得加上快读。
ll n,m,k;
ll x,y;
string s;
ll corn=1;
ll mod=1e9+7;
ll sum[400010];
__int128 nxt[400010][70];
ll ask(ll x) // 1~x 有几个 1
{
return sum[x%n]+sum[n]*(x/n);
}
ll query(ll l,ll r){// l~r 中有几个 1
return ask(r)-ask(l-1);
}
ll f(__int128 x)
{
if(x%n==0)
return n;
return x%n;
}
ll corn2=1;
void solve()
{
_clear();
cin>>n>>m>>k>>s;
s=s+s;
s=' '+s;
forl(i,1,n)
corn&=s[i]=='0',
corn2&=s[i]=='1';
if(corn)
{
while(k--)
cin>>x>>y,
cout<<(x+y)%mod<<endl;
return ;
}
if(corn2)
{
while(k--)
cin>>x>>y,
cout<<(x+(y%mod)*(m%mod))%mod<<endl;
return ;
}
forl(i,1,n*2)
sum[i]=sum[i-1]+(s[i]=='1');
forl(i,1,n)
{
ll L=i+1,R=i+m;
while(L<R)
{
ll Mid=(L+R)/2;
if(query(Mid+1,i+m)>=1)
L=Mid+1;
else
R=Mid;
}
if(query(L,L)>=1)
nxt[i][0]=L-i;
else
nxt[i][0]=1;
}
forl(j,1,62)
forl(i,1,n)
nxt[i][j]=(nxt[i][j-1]+nxt[f(i+nxt[i][j-1])][j-1]);
while(k--)
{
cin>>x>>y;
ll ans=x%mod;
forr(i,62,0)
if(y&(1ll<<i))
{
x%=n;
if(x==0)
x=n;
ans=(ans+nxt[x][i]%mod)%mod;
x+=nxt[x][i]%n;
}
cout<<ans<<endl;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?