Loading

P6835 [Cnoi2020]线形生物

链接

做期望还不是很熟练啊,这个题做了一个小时才做出来。

想必各位大佬都是秒切。

这个题是一个不是很裸的转移带环处理,但实际上还是很裸。

我们设 \(f_i\) 表示现在在 \(i\) ,想要到 \(n\) 的期望步数。

我们把样例 \(4\) 画一下,如图:

不难发现有一下转移:

\[\begin{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\) 表示出来。

比如上面这个例子,就有:

\[\begin{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\n",i,c[i]);putchar('\n');
    for(int i=n;i>=1;i--){
        ans+=c[i];ans%=mod;
    }
    printf("%lld\n",ans);
    return 0;
}

时间复杂度 \(O(n+m)\)

posted @ 2021-07-13 09:39  hyl天梦  阅读(52)  评论(0编辑  收藏  举报