zoukankan      html  css  js  c++  java
  • 计数dp做题笔记

    YCJS 3924 饼干

    Description

    给定一个长度为\(n\)的序列,序列每个元素的取值为\([1,x]\),现在给定\(q\)个区间,求在所有取值方案中,区间最小值的最大值的期望是多少?(答案对1e9+7取模)

    \(n,q,x\le 2000\)

    Solution

    • 首先对于这种区间问题,要找到一种转移顺序的话,就要使得这个序列有序(可以是左右端点递增)。

    • 然后对于这道题目,考虑枚举最小值的最大值\(ans\)

    • 性质1:如果区间a包含区间b,那么\(ans\)只可能存在于区间b中。

    • 所以可以通过该性质删去一些区间,然后转移就有序了。

    • 性质2:如果区间有序,那么所有有被区间包含的点\(a_i\),包含它们的区间的编号也是递增的。

    • 那么可以比较容易定义出一个\(O(n^3)\)的转移。

    • 首先枚举ans,然后每个区间就一定要存在至少一个点的权值\(\le ans\) 然后答案为ans的方案就是\(F[ans]-F[ans-1]\)

    • 定义\(dp_{i,j}\) 为枚举到第i个点,满足到第j个区间的方案数,发现转移是\(O(1)\)的,因为只用知道当前点要填的数是否>ans就可以计算出转移到的状态。

    • 然后化简状态,令\(dp_i\) 表示第i个点的权值\(<=ans\),且填到第i个点仍是合法的方案数。

    • 定义 \(L_i\)表示覆盖第i个点的区间的最小编号,\(R_i\)表示覆盖第i个点的最大编号

    • 那么转移方程为$$dp_i=ans\sum\limits _{R_j\ge L_i-1} dp_j(x-ans)^{i-j-1}$$

    • 进一步化简$$dp_i=ans(x-ans)^i\sum \limits_{R_j\ge L_i-1} dp_j*(x-ans)^{-j-1}$$

    • 由性质2可得,满足条件的j是一端连续的区间,所以可以用前缀和维护后面一端累和,然后转移就是\(O(1)\)的了。

    • 总复杂度\(O(n^2)\)

    hihocoder 1758 加减

    [数位dp+概率期望]

    Description

    对于一个二进制位数x ,有50%的概率 -lowbit(x),有50%的概率 +lowbit(x)

    令Sum[x]表示x变化为0的期望变化次数,求 \(\sum \limits _{i=l}^{r} Sum[i]\) 的值 答案对998244353取模

    • \(l\le r< 2^{31}\)

    Solution

    分析操作性质

    对于两个等概率操作,-lowbit(x)等于减去最小的二进制位,+lowbit(x)等于从最小的二进制位开始进位

    需要记录信息及转移

    进行数位dp,记f[1]为后面的数进位过来的期望步数,g[1]为从后面进位过来的概率总和

    如果当前点为0的话,那么在此时,当前位为lowbit,需要进行一次操作,有50%的概率进位到前面

    所以当前位的 \(f_{now}[1]=\frac{1}{2}\times (g[1]+f[1])\)\(g_{now}[1]=\frac{1}{2}\times g[1]\),同理当前位为0的情况

    Code

    #include<cstdio>
    #include<cstring>
    #define FOR(i,x,y) for(int i=(x),i##_END=(y);i<=i##_END;++i)
    #define DOR(i,x,y) for(int i=(x),i##_END=(y);i>=i##_END;--i)
    const int P=998244353;
    typedef long long LL;
    int fast(int x,int n){int res=1;for(;n;n>>=1,x=(LL)x*x%P)if(n&1)res=(LL)res*x%P;return res;}
    inline void add(int &x,int y){x+=y;if(x>=P)x-=P;}
    struct node{
    	int f[2],g[2];
    	node(){f[0]=f[1]=0,g[0]=g[1]=0;}
    }dp[36],T;
    bool mark[36];
    int limits[36],H,Inv;
    
    
    node dfs(int x,bool f){ 
    	if(!x)return T;
    	if(!f&&mark[x])return dp[x];
    	node D;
    	FOR(i,0,f?limits[x]:1){
    		node E=dfs(x-1,f&&i==limits[x]);
    		if(i==1){
    			add(D.f[1],E.f[1]);
    			add(D.g[1],E.g[1]);
    			add(D.f[0],(LL)E.f[0]*Inv%P);
    			add(D.f[0],(LL)E.g[0]*Inv%P);
    			add(D.g[0],(LL)E.g[0]*Inv%P);
    			add(D.f[1],(LL)E.f[0]*Inv%P);
    			add(D.f[1],(LL)E.g[0]*Inv%P);
    			add(D.g[1],(LL)E.g[0]*Inv%P);
    		}else {//i==0
    			add(D.f[0],E.f[0]);
    			add(D.g[0],E.g[0]);
    			add(D.f[1],(LL)E.f[1]*Inv%P);
    			add(D.f[1],(LL)E.g[1]*Inv%P);
    			add(D.g[1],(LL)E.g[1]*Inv%P);
    			add(D.f[0],(LL)E.f[1]*Inv%P);
    			add(D.f[0],(LL)E.g[1]*Inv%P);
    			add(D.g[0],(LL)E.g[1]*Inv%P);
    		}
    	}
    	if(!f){
    		mark[x]=true;
    		dp[x]=D;
    	}
    	return D;
    }
    
    int Solve(int x){
    	if(!x)return 0;
    	H=0;
    	memset(limits,0,sizeof limits);
    	while(x)limits[++H]=x%2,x/=2;
    	node res=dfs(H,1);
    	return ((LL)res.f[0]+res.f[1]+res.g[1]*2)%P;
    }
    
    int main(){
    	T.f[0]=0,T.f[1]=0;
    	T.g[0]=1,T.g[1]=0;
    	
    	int L,R;
    	Inv=fast(2,P-2);
    	scanf("%d%d",&L,&R);
    	printf("%d\n",(Solve(R)-Solve(L-1)+P)%P);
    	return 0;
    }
    
  • 相关阅读:
    896. Monotonic Array单调数组
    865. Smallest Subtree with all the Deepest Nodes 有最深节点的最小子树
    489. Robot Room Cleaner扫地机器人
    JavaFX
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
  • 原文地址:https://www.cnblogs.com/Zerokei/p/9689668.html
Copyright © 2011-2022 走看看