• 模拟赛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;
    }
    
  • 相关阅读:
    10.25T2 二维线段树
    10.25T1 模拟+栈
    10.24T3 解方程 取模意义下运算+秦九韶算法
    10.24T2 树链剖分
    10.24T1 树形DP
    10.23T3 杨辉三角上做莫队
    10.23T2 二分+二分图(滑稽)
    10.23T1 杨辉三角
    10.22T6 水题
    10.22T4 模拟DP
  • 原文地址:https://www.cnblogs.com/wzzyr24/p/12749833.html
Copyright © 2020-2023  润新知