AtCoder Beginner Contest 270 G,Ex
y1s1,G和Ex在推等比数列式子上是相似的。
G
前置知识:BSGS(其实就是根号讨论)
首先我们展开这个递归式:
感觉第一项有些难搞,故我们设,为:
之后我们套用BSGS的方法,设答案为。
则:
提取公因式:
我们先进行预处理:枚举到,将 模的值存入map中,如果已经在map中有这个值了,那么我们取最小的(因为我们要让答案最小)。
之后枚举,查询是否在map中,如果在,更新答案,其中是map中预处理得到的最小的值。
若我们设,时间复杂度最优,大概是。
Ex
一道好题。
首先个计数器是不好记录状态的。
一、简化并列出状态
我们设状态,其中是第个计数器的值。
可以发现,若,则我们就满足了,并且,其实我们在每次操作最多减去,故当时,我们就终止操作。
这样有什么好处呢?
转移是更方便的:
我们设,满足,则:
-
如果我们将第个计数器清零,且,那么。(因为<k,也一定不超过,此时只能是由的转移而来)
-
如果我们将第个计数器清零,且,那么。 (因为>k,将第个计数器清零后,故此时)
至此,我们发现,不仅减少状态数,并且转移还是简单的。
我们可以列出DP方程:表示状态为时的期望操作次数,则,容易发现,这个转移是有环的。
二、处理转移有环的问题
我首先感觉这题和 https://atcoder.jp/contests/abc189/tasks/abc189_f 是类似的,设不过没继续往下想。
这题题解有一个非常巧妙的“移项去环”的方法:
我们将两侧乘上:
两边同时加上:
设,则:
将移到左边,移到右边:
即:
此时,我们发现,右侧的每个下标都大于左侧,那么这个转移是可行的。
并且最终答案是。
时间复杂度为或,TLE,怎么办?
三、优化
我们发现,对于到,时,。(注意我们将下标统一了,现在的其实是时刻的)那么转移的系数、常数都是相同的。
重设为时的。
设,则类似之前的G题,将递推式展开:
前面是一个快速幂,后面是一个等比数列,可以在的时间复杂度内求出。
由于题中保证,故答案等于。
注意的情况。
总时间复杂度为。
代码:
#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl
using ll=long long;
const int maxn=200005;
const ll mod=998244353;
ll n,sum,a[maxn],P[maxn];
ll qpow(ll x,ll y) {
if(y==0ll) return 1ll;
ll ret=qpow(x,y>>1ll);
ret=ret*ret%mod;
if(y&1ll) ret=ret*x%mod;
return ret;
}
int main() {
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
//P[n]=0 and P[1] is the answer (P[i]=F[a[n]]-F[a[i]])
for(int i=n-1;i>=1;i--) {
ll alpha=n*qpow(i,mod-2ll)%mod;
ll beta=(n-sum+mod)%mod*qpow(i,mod-2ll)%mod;
ll theta=P[i+1];
ll delta=a[i+1]-a[i];
if(delta==0) P[i]=theta;
else P[i]=(theta*qpow(alpha,delta)%mod+(1-qpow(alpha,delta)+mod)%mod*qpow((1-alpha+mod)%mod,mod-2ll)%mod*beta%mod)%mod;
(sum+=P[i])%=mod;
}
printf("%lld\n",P[1]);
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战