ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2021.牛客暑假多校 第四场 补题

2021-08-10 14:29:54  阅读:214  来源: 互联网

标签:第四场 int res sum 多校 生成 补题 pj dp


  1. B题 https://ac.nowcoder.com/acm/contest/11255/B 期望DP

大意:现有一个随机数生成器,每次生成1~100的数字,概率为 p i p_i pi​​ ,现在有以下阶段,(1)生成一个数 x。 (2) 若生成的数 x 不小于之前任意一个生成的数重复(1)否决进行(3)。(3)计算得分,未生成数的个数的平方并结束生成。

思路:很容易看出是期望dp,比赛的时候题目理解错了,思考方式完全错了。官方解给的是用生成函数写,我们这里用期望dp。对于求平方的期望 E ( x 2 ) E(x^2) E(x2)​,我们一般先求出 E(x)。因为 E ( x 2 ) E(x^2) E(x2) 在进行状态转移时要用到 E(x)。即 E ( ( x + 1 ) 2 ) = E ( x 2 + 2 x + 1 ) = E ( x 2 ) + 2 E ( x ) + 1 E((x+1)^2)=E(x^2+2x+1)=E(x^2)+2E(x)+1 E((x+1)2)=E(x2+2x+1)=E(x2)+2E(x)+1

而且此题是可以无限次的生成随机数的,所以根据步数进行状态定义和状态转移是行不通的.

先求 E(x)的:

我们用 f i f_i fi​​​ 表示当前生成的随机数中最大值为 i 再 生成一个数的期望。

再生成一个数是小于 i 的 ∑ j = 1 i − 1 p j ∗ 1 \sum_{j=1}^{i-1}{p_j} * 1 ∑j=1i−1​pj​∗1

在生成一个数是大于等于 i 的 ∑ j = i n ( f j + 1 ) ∗ p j \sum_{j=i}^{n} (f_j+1)*p_j ∑j=in​(fj​+1)∗pj​​

观察下面那个状态转移方程我们会发现 j 从 i 开始的话每次更新 f i f_i fi​​的时候还要用到 f i f_i fi​​ ,显然是没办法更新的,所以我们把 j=i 的给单独拉出来。

所以下面那个状态转移方程可变为 ( f i + 1 ) p i + ∑ j = i + 1 n ( f j + 1 ) ∗ p j (f_i+1)p_i + \sum_{j=i+1}^{n} (f_j+1)*p_j (fi​+1)pi​+∑j=i+1n​(fj​+1)∗pj​​​

即 f i = ∑ j = 1 i − 1 p j ∗ 1 + ( f i + 1 ) p i + ∑ j = i + 1 n ( f j + 1 ) ∗ p j f_i=\sum_{j=1}^{i-1}{p_j} * 1+ (f_i+1)p_i + \sum_{j=i+1}^{n} (f_j+1)*p_j fi​=∑j=1i−1​pj​∗1+(fi​+1)pi​+∑j=i+1n​(fj​+1)∗pj​

化简得 f i = 1 + ∑ j = i + 1 n f j ∗ p j ( 1 − p i ) f_i=\frac{1+\sum_{j=i+1}^{n} f_j*p_j}{(1-p_i)} fi​=(1−pi​)1+∑j=i+1n​fj​∗pj​​​​​ 显然这样就可以递推更新了

再来求 E ( x 2 ) E(x^2) E(x2)​ 的:

我们用 d p i dp_i dpi​​ 表示当前生成的随机数中最大值为 i 再 生成一个数的期望。

同理: d p i = ∑ j = 1 i − 1 p j ∗ 1 + ( d p i + 2 f i + 1 ) p i + ∑ j = i + 1 n ( d p j + 2 f j + 1 ) ∗ p j dp_i=\sum_{j=1}^{i-1}{p_j} * 1+ (dp_i+2f_i+1)p_i + \sum_{j=i+1}^{n} (dp_j+2f_j+1)*p_j dpi​=∑j=1i−1​pj​∗1+(dpi​+2fi​+1)pi​+∑j=i+1n​(dpj​+2fj​+1)∗pj​​​

化简得: d p i = 1 + 2 p i f i + ∑ j = i + 1 n ( d p j + 2 f j ) ∗ p j 1 − p i dp_i=\frac {1 + 2p_i f_i + \sum_{j=i+1}^{n} (dp_j+2f_j)*p_j}{1-p_i} dpi​=1−pi​1+2pi​fi​+∑j=i+1n​(dpj​+2fj​)∗pj​​​

最终结果:我们假设第一个生成的数 i 显然第一个生成的数 1~n 都有可能,所以就是把所有可能的结果相加:也就是 d p 0 dp_0 dp0​​

所以我们要递推到 i=0.

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N=110,M=998244353;
typedef long long LL;
LL qmi(LL a,LL b)
{
    LL res=1;
    while(b)
    {
        if(b&1)res=res*a%M;
        a=a*a%M;
        b>>=1;
    }
    return res%M;
}
LL p[N],f[N],dp[N],n,ps;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>p[i],ps=(ps+p[i])%M;
    ps=qmi(ps,M-2);
    for(int i=1;i<=n;i++)p[i]=p[i]*ps%M;
    LL s=0;
    for(int i=n;i>=1;i--)
    {
        f[i]=(1+s)*qmi((1-p[i]+M)%M,M-2)%M;
        s=(s+f[i]*p[i])%M;
    }
    s=0;
    for(int i=n;i>=0;i--)
    {
        dp[i]=(1+2*p[i]*f[i]+s)%M*qmi((1-p[i]+M)%M,M-2)%M;
        s=(s+(dp[i]+2*f[i])*p[i])%M;
        //cout<<dp[i]<<"\n";
    }
    cout<<dp[0]<<"\n";
    return 0;
}

总结:期望DP 重要的是怎么计算期望,只有先会怎么计算期望,才有可能写出状态转移方程。

  1. C题 https://ac.nowcoder.com/acm/contest/11255/C 思维构造,签到
  2. E题 https://ac.nowcoder.com/acm/contest/11255/E 线段树+异或/ 线段差分+异或,思维

大意:有一颗 n 个节点的树,先给出所有的边权值,边权值代表边两边的点权的异或值,并给出点权的取值范围 [ l i , r i ] [l_i,r_i] [li​,ri​],问一共有多少种符合条件的情况。 n < = 1 e 5 , 0 < = l < = r < = 2 3 0 n<=1e5, 0<=l<=r<=2^30 n<=1e5,0<=l<=r<=230

思路:首先需要想到的一点,一旦我们确定了任意一个点的值,我们进而就可以推出所有点的值,并且对于任意一点异或上x,由于异或的特点就行相当于其他的点也分别异或上x。所以我们不妨先假设根节点的值为0,先求出每个点的值,这样不一定是合法的,但我们可以通过根节点异或上x进行调整,也就将问题转化成了对于 每个点都有 l[i] <=(w[i]异或x)<=r[i](1<=i<=n), 求满足条件的x的个数。进一步转化也就是我们把数看成一个数轴,对于每个i 我们求出合法的若干个x的值就在相应位置加1,看最后有多少个位置的值是n。对于一段区间+1的操作,显然我们可以用差分数组进行,但是x最大能取到 1e9,直接用肯定不行,所以我们用的是“差分数组的思想”。但是每次求满足一段区间的 [ l i , r i ] [l_i,r_i] [li​,ri​]​,所以这里我们用到经典操作,区间问题转化成前驱问题,我们先求满足 [ 0 , l i − 1 ] [0,l_i-1] [0,li​−1]​ 在对应位置标记为 -1,再求 [ 0 , r i ] [0,r_i] [0,ri​]​ 标记为 1,这样也是不会影响我们的最终结果的。接下来的问题就是怎么求合法的x了,即求满足(a异或x)<= b的,x的个数。这部分显然就是之前做字典树经常用到的了,不同的是这里不需要建立字典树,对于某一位显然就 00,01,10,11 四种情况(前面的0或1代表a,后面的代表b),对于b这一位是0的,显然只有当 x 的这一位和 a 的这一位相同才有可能,对于b这一位是1的,x和a这一位相同的一定是可以的,后面的为可以随便取,这一位不同的也是有可能的。

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N=100010;
typedef pair<int,int> PII;
int h[N],e[N*2],ne[N*2],w[N*2],idx;
int val[N],l[N],r[N],n;
bool st[N];
vector<PII> vol[2];
void add(int a,int b,int c)
{
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u)
{
	st[u]=1;
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int j=e[i],k=w[i];
		if(st[j])continue;
		val[j]=k^val[u];
		dfs(j);
	}
}
void dfs1(int id,int x,int y,int bt,int now)
{
	if(bt==-1)
	{
		vol[id].push_back({now,now});
		return ;
	}
	int a=x>>bt&1,b=y>>bt&1;
	if(b==1)
	{
		if(a==1) vol[id].push_back({now+(1<<bt),now+(1<<(bt+1))-1});
		else vol[id].push_back({now,now+(1<<bt)-1});

		dfs1(id,x,y,bt-1,now+((a^1)<<bt));
	}
	else dfs1(id,x,y,bt-1,now+(a<<bt));

}
void solve()
{	
	cin>>n;
	for(int i=1;i<=n;i++)cin>>l[i]>>r[i];
	for(int i=1;i<n;i++)
	{
		int a,b,c;
		cin>>a>>b>>c;
		add(a,b,c);
		add(b,a,c);
	}
	dfs(1);
	for(int i=1;i<=n;i++)
	{
		if(l[i]>0)dfs1(0,val[i],l[i]-1,29,0);
		dfs1(1,val[i],r[i],29,0);
	}
	vector<PII> res;
	for(auto &x:vol[0])
	{
		res.push_back({x.first,-1});
		res.push_back({x.second+1,1});
	}
	for(auto &x:vol[1])
	{
		res.push_back({x.first,1});
		res.push_back({x.second+1,-1});
	}
	sort(res.begin(),res.end());
	int t=0,ans=0;

	for(int i=0;i<res.size();i++)
	{
		t+=res[i].second;
		if(t==n&&i+1<res.size())ans+=res[i+1].first-res[i].first;
	}
    cout<<ans<<"\n";
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	memset(h,-1,sizeof h);
    solve();
	return 0;
}

总结:对于差分要活用,区间问题转化成前驱问题。

  1. F 题 https://ac.nowcoder.com/acm/contest/11255/F 博弈,思维,签到

大意:给定一个无环的无向图,不一定全连通,有两种操作方式,(1)选择一条边,删除它,(2)选择一个连通块删除它。两人轮流操作,不能操作的判输。

思路:比赛的时候想复杂了,用SG 想了很久,最后是判断连通块的数量。其实没这么麻烦。对于第一种操作,使得边数 -1,对于第二种操作使得点数-k,边数 -(k-1),但是两种操作使得边数和点数的和都是以奇数方式相减,所以直接判断点数+边数的奇偶就行了。

标签:第四场,int,res,sum,多校,生成,补题,pj,dp
来源: https://blog.csdn.net/m0_51488693/article/details/119569187

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有