做期望还不是很熟练啊,这个题做了一个小时才做出来。
想必各位大佬都是秒切。
这个题是一个不是很裸的转移带环处理,但实际上还是很裸。
我们设 (f_i) 表示现在在 (i) ,想要到 (n) 的期望步数。
我们把样例 (4) 画一下,如图:
不难发现有一下转移:
[egin{cases}
f_1=frac12 (f_1+1+f_2+1) \
f_2=f_3+1\
f_3=frac{1}{2}(f_4+1+f_1+1)\
f_4=frac{1}{2}(f_5+1+f_2+1)\
f_5=frac{1}{2}(f_6+1+f_1+1)
end{cases}
]
(f_6) 在画图的时候忘画上去了。以及这个东西画不出来自环。
请各位自行脑补
然后我们就能够发现,(f_1) 可以用 (f_3) 表示出来,同样的 (f_2) 可以用 (f_4) 表示出来,(f_1) 可以用 (f_5) 表示出来。
比如上面这个例子,就有:
[egin{cases}
f_1=f_2+2\
f_2=f_3+1\
f_3=f_4+5\
f_4=f_5+8\
f_5=f_4+19
end{cases}
]
然后我们就可以累积后面的那个数以得到答案。
至于求解后面的那个数,我们把图建出来,用前缀和维护即可。
代码:
#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 1000100
#define M 3000200
using namespace std;
const int INF=0x3f3f3f3f;
const ll mod=998244353;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
struct edge{
int to,next;
inline void intt(int to_,int ne_){
to=to_;next=ne_;
}
};
edge li[M];
int head[N],tail;
inline void add(int from,int to){
li[++tail].intt(to,head[from]);
head[from]=tail;
}
// ll inv[N];
// inline ll ksm(ll a,ll b,ll mod){
// ll res=1;
// while(b){
// if(b&1) (res*=a)%=mod;
// a=a*a%mod;b>>=1;
// }
// return res;
// }
ll id,n,m,sum[N],c[N],ans;
int main(){
freopen("my.in","r",stdin);
freopen("my.out","w",stdout);
read(id);read(n);read(m);
for(int i=1;i<=n;i++) add(i,i+1);
for(int i=1;i<=m;i++){
int from,to;read(from);read(to);
add(from,to);
}
for(int i=1;i<=n;i++){
for(int x=head[i];x;x=li[x].next){
int to=li[x].to;
if(to!=i+1) c[i]+=(sum[i-1]-sum[to-1]+1)%mod;
else c[i]+=1;
c[i]%=mod;
}
sum[i]=sum[i-1]+c[i];sum[i]%=mod;
}
for(int i=1;i<=n;i++) printf("i:%d c:%lld
",i,c[i]);putchar('
');
for(int i=n;i>=1;i--){
ans+=c[i];ans%=mod;
}
printf("%lld
",ans);
return 0;
}
时间复杂度 (O(n+m))。