题目链接:https://atcoder.jp/contests/arc170/tasks/arc170_e
题目大意:现在有一个 $n$ 个点的环,然后每个点的权值 $a_i$ ,一开始都是 $-1$ ,然后有个队列,初始只有一个 $(1,0)$,
然后每次弹出队首 $(d,v)$,若 $a_d=-1$ ,则:
- $a_d=v$ 。
- 从小到大考虑 $d$ 相邻的权值为 $-1$ 的邻居 $x$ ,然后有 $p$ 的概率把 $(x,v+1)$ 加入队首,否则加入队尾。
问最后所有点的权值和的期望。
做法
唐,太唐了,转换完题意不会做,一个经典的二阶期望不会,唐,太烫了。
首先,这道题目显然可以转换成这个题意:
现在有一个长度为二的数组:$a[0]=-1,a[1]=0$ ,然后 $type=0$ ,现在进行 $n-1$ 轮:
a[type]++
。
- 有 $p$ 的概率不发生变化,有 $1-p$ 的概率
type^=1
。
问最后 $\frac{a0}{2}+\frac{a1}{2}$ 的期望值。
首先,多少阶的期望都是能做的,开对应阶数个状态就行了,像自然数幂求和那样推一下式子就行了。
这里是二阶期望,开两个状态即可。
但这里由于数组有两个位置,所以还要再多开一个状态,总共三个状态,分别为:
$f_{ans}[n]$ 表示 $n$ 轮后的期望答案,$f_0[n]$ 表示 $a[type]$ 的期望值,$f_1[n]$ 表示 $a[1-type]$ 的期望值。
则式子为:
然后直接矩阵快速幂就行了。
时间复杂度:$O(T\log{n})$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| #include<bits/stdc++.h> using namespace std; typedef long long LL; const LL mod=998244353; struct Matrix{ LL a[4][4]; Matrix(){ memset(a,0,sizeof(a)); } }O,tr; Matrix operator*(Matrix x,Matrix y){ Matrix z; for(int i=0;i<=3;i++){ for(int j=0;j<=3;j++){ for(int k=0;k<=3;k++){ z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j])%mod; } } } return z; } Matrix operator+(Matrix x,Matrix y){ Matrix z; for(int i=0;i<=3;i++){ for(int j=0;j<=3;j++)z.a[i][j]=(x.a[i][j]+y.a[i][j])%mod; } return z; } Matrix operator%(Matrix x,LL y){return x;}
template<class T> T ksm(T x,LL y,T o){ T ans=o; while(y){ if(y&1)ans=ans*x%mod; x=x*x%mod;y>>=1; } return ans; } int main(){ for(int i=0;i<=3;i++){ O.a[i][i]=1; } int T;scanf("%d",&T); while(T--){ LL n,p;scanf("%lld%lld",&n,&p); p=p*ksm(100ll,mod-2,1ll)%mod; LL pn=(1-p+mod)%mod; tr.a[0][0]=tr.a[1][0]=tr.a[3][0]=1; tr.a[1][1]=tr.a[3][1]=p;tr.a[2][1]=pn; tr.a[1][2]=tr.a[3][2]=pn;tr.a[2][2]=p; tr.a[3][3]=1;
Matrix ans=ksm(tr,n,O); printf("%lld\n",(ans.a[3][0]-ans.a[1][0]+mod)%mod); } return 0; }
|
我当时其实写出了一个正确的式子,但我不知道怎么推了,在文章的最后放一下吧,悲。
唐,怎么每次碰到dp+矩阵快速幂的题都不会做啊,悲。