• 计数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;
    }
    
  • 相关阅读:
    (1)ASCⅡ码与一般乘除与逻辑指令
    (2)串指令的传送
    【转】伟大的代码(97年的Mekka ’97 4K Intro比赛的一等奖作品)汇编机器码
    第四次游戏革命:全息游戏 from:http://www.cnblogs.com/alamiye010/archive/2012/08/15/2640881.html
    sqlce wp
    wp7 blogs
    单例的两种实现方式
    C# event from:http://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html#a4
    wp7——sqlite数据库操作 from:http://blog.csdn.net/wp_lijin/article/details/7370790
    Linq C#增删改查
  • 原文地址:https://www.cnblogs.com/Zerokei/p/9689668.html
Copyright © 2020-2023  润新知