模拟赛2 题解

这次模拟赛最后一道是提答题,就不写题解了。


CF93E Lostborn

orz
这题……emmm,我无话可说。
小范围记忆化,大范围递归求解……复杂度 (O(ksqrt{n}))
(f(i,j)) 表示前 (j) 个数中不被 (a_i,a_{i+1},dots,a_n) 整除的个数,答案即为 (f(1,n))。状态转移方程为 (f(i,j)=f(i+1,j)-f(i+1,j/a_i))
转移方程是个容斥,可以在小范围内把式子展开理解一下。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=105,M=2e5;
ll n;
int k,f[N][M+5],a[N];

ll F(int i,ll j)
{
	if(i>k||j==0) return j;
	if(j<=M&&f[i][j]!=-1) return f[i][j];
	ll ans=F(i+1,j)-F(i+1,j/a[i]);
	if(j<=M) f[i][j]=ans;
	return ans;
}

int main()
{
	scanf("%I64d%d",&n,&k);
	for(int i=1;i<=k;++i) scanf("%d",a+i);
	sort(a+1,a+k+1,greater<int>());
	memset(f,-1,sizeof(f));
	printf("%I64d
",F(1,n));
	return 0;
}

CF712E Memory and Casinos

神仙题啊啊啊啊啊
(f(l,r)) 表示从 (l) 开始走,不到 (l-1) 且走出 (r) 的概率(即不会游戏失败),(g(l,r)) 表示表示从 (r) 开始走,不到 (r+1) 且走出 (l) 的概率。现在我们用分治的方式来计算这个式子,又因为题目还带了操作,容易想到用线段树来维护。现在考虑合并两个区间的 (f_1=f(l,mid),f_2=f(mid+1,r),g_1=g(l,mid),g_2=g(mid+1,r))(还有 (f(l,r)=f,g(l,r)=g))。

[f=f_1f_2+f_1(1-f_2)(1-g_1)f_2+f_1(1-f_2)^2(1-g_1)^2f_2+dots ]

即直接走过去、转一圈、转两圈、一直转下去的情况之和。
发现后方是个等比数列,于是答案就是

[f=f_1f_2frac{1-((1-f_2)(1-g_1))^{infty}}{1-(1-f_2)(1-g_1)}=frac{f_1f_2}{1-(1-f_2)(1-g_1)} ]

同理可得

[g=frac{g_1g_2}{1-(1-f_2)(1-g_1)} ]

特别地,(f(l,l)=p_l,g(l,l)=g_l)

#include <bits/stdc++.h>
using namespace std;

const int N=1e5+5;
struct Node
{
	int l,r;
	double f,g;
	#define l(x) t[x].l
	#define r(x) t[x].r
	#define f(x) t[x].f
	#define g(x) t[x].g
}t[N<<2];
double p[N];
int n,q;

inline void pushup(int rt)
{
	f(rt)=f(rt<<1)*f(rt<<1|1)/(1.0-(1.0-f(rt<<1|1))*(1.0-g(rt<<1)));
	g(rt)=g(rt<<1)*g(rt<<1|1)/(1.0-(1.0-f(rt<<1|1))*(1.0-g(rt<<1)));
}

void build(int rt,int l,int r)
{
	l(rt)=l,r(rt)=r;
	if(l==r) {f(rt)=p[l],g(rt)=1.0-p[l]; return;}
	int mid=l+r>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	pushup(rt);
}

void change(int rt,int pos,double val)
{
	if(l(rt)==r(rt)) {f(rt)=val,g(rt)=1.0-val; return;}
	int mid=l(rt)+r(rt)>>1;
	if(pos<=mid) change(rt<<1,pos,val);
	else change(rt<<1|1,pos,val);
	pushup(rt);
}

Node query(int rt,int l,int r)
{
	if(l<=l(rt)&&r>=r(rt)) return t[rt];
	int mid=l(rt)+r(rt)>>1;
	if(r<=mid) return query(rt<<1,l,r);
	if(l>mid) return query(rt<<1|1,l,r);
	Node ls=query(rt<<1,l,r),rs=query(rt<<1|1,l,r);
	Node ans=(Node){0,0,ls.f*rs.f/(1.0-(1.0-rs.f)*(1.0-ls.g))
	                   ,ls.g*rs.g/(1.0-(1.0-rs.f)*(1.0-ls.g))};
	return ans;
}

int main()
{
	scanf("%d%d",&n,&q);
	for(int i=1,l,r;i<=n;++i)
	{
		scanf("%d%d",&l,&r);
		p[i]=1.0*l/r;
	}
	build(1,1,n);
	while(q--)
	{
		int op; scanf("%d",&op);
		if(op==1)
		{
			int i,x,y; scanf("%d%d%d",&i,&x,&y);
			change(1,i,1.0*x/y);
		}
		else
		{
			int l,r; scanf("%d%d",&l,&r);
			printf("%f
",query(1,l,r).f);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/wzzyr24/p/12749833.html