zoukankan      html  css  js  c++  java
  • CF1286D LCC

    一、题目

    点此看题

    二、解法

    这道题其实很清真的啊,我怎么做不出来呢?

    首先有一个 ( t observation):最小碰撞只会发生在相邻两个粒子的碰撞中。

    相邻两个粒子只有三种碰撞情况,我们先把它讨论出来。然后考虑枚举产生最小碰撞时间的是某个碰撞组合,导致的限制是时间比它小的碰撞组合不能选取。

    (f[i][0/1]) 表示这一位向左(/)向右走,(l_i[0/1][0/1]) 表示这种碰撞组合是否不能选取,满足限制的概率:

    [f[i][1]leftarrow p[i] imes(f[i-1][0]cdot l_i[0][1]+f[i-1][1]cdot l_i[1][1]) ]

    [f[i][0]leftarrow (1-p[i]) imes(f[i-1][1]cdot l_i[0][0]+f[i-1][1]cdot l_i[1][0]) ]

    上面的转移很容易写成矩阵的形式,具体实现就是把每种碰撞组合排序,然后做动态 (dp) 即可,时间复杂度 (O(nlog n))

    三、总结

    当期望题中出现最值时,是很难记录在状态里面的,那么我们直接枚举!

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int M = 100005;
    const int MOD = 998244353;
    #define int long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,ans,a[M],b[M],p[M];
    struct mat
    {
    	int a[2][2];
    	mat() {memset(a,0,sizeof a);}
    	mat operator * (const mat &b) const
    	{
    		mat r;
    		for(int i=0;i<2;i++)
    			for(int j=0;j<2;j++)
    				for(int k=0;k<2;k++)
    					r.a[i][k]=(r.a[i][k]+a[i][j]*b.a[j][k])%MOD;
    		return r;
    	}
    }tr[4*M],mt[M];
    struct node
    {
    	int l,v,p,op;
    	bool operator < (const node &r) const
    	{
    		return l*r.v<r.l*v;
    	}
    }s[3*M];
    int qkpow(int a,int b)
    {
    	int r=1;
    	while(b>0)
    	{
    		if(b&1) r=r*a%MOD;
    		a=a*a%MOD;
    		b>>=1;
    	}
    	return r;
    }
    void add(int i,int l,int r,int id,mat x)
    {
    	if(l==r)
    	{
    		tr[i]=x;
    		return ;
    	}
    	int mid=(l+r)>>1;
    	if(mid>=id) add(i<<1,l,mid,id,x);
    	else add(i<<1|1,mid+1,r,id,x);
    	tr[i]=tr[i<<1]*tr[i<<1|1];
    }
    signed main()
    {
    	n=read();
    	for(int i=1;i<=n;i++)
    	{
    		a[i]=read();b[i]=read();
    		p[i]=read()*qkpow(100,MOD-2)%MOD;
    	}
    	for(int i=1;i<n;i++)
    	{
    		int l=a[i+1]-a[i];
    		s[++m]=node{l,b[i+1]+b[i],i+1,0};
    		if(b[i]<b[i+1]) s[++m]=node{l,b[i+1]-b[i],i+1,1};
    		if(b[i]>b[i+1]) s[++m]=node{l,b[i]-b[i+1],i+1,2};
    	}
    	for(int i=1;i<=n;i++)
    	{
    		mt[i].a[0][0]=mt[i].a[1][0]=MOD+1-p[i];
    		mt[i].a[0][1]=mt[i].a[1][1]=p[i];
    		add(1,1,n,i,mt[i]);
    	}
    	sort(s+1,s+1+m);
    	for(int i=1;i<=m;i++)
    	{
    		int op=s[i].op,x=s[i].p;
    		int val=s[i].l*qkpow(s[i].v,MOD-2)%MOD;
    		mat t1=mt[x],t2;
    		if(op==0) t2.a[1][0]=MOD+1-p[x],t1.a[1][0]=0;
    		if(op==1) t2.a[0][0]=MOD+1-p[x],t1.a[0][0]=0;
    		if(op==2) t2.a[1][1]=p[x],t1.a[1][1]=0;
    		add(1,1,n,x,t2);
    		ans=(ans+val*(tr[1].a[0][0]+tr[1].a[0][1]))%MOD;
    		add(1,1,n,x,t1);mt[x]=t1;
    	}
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    2016-10-17: source insight插件
    Reactor模式通俗解释
    2016-09-19: linux后台运行
    2016-08-16: 检测函数是否存在的C++模板
    2016-08-16: copy-and-swap
    2016-08-15:从YUV420P中提取指定大小区域
    2016-08-15: C++ traits
    2016-08-05:samba服务器配置
    LINQ 根据指定属性名称对序列进行排序
    Resharper
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15234485.html
Copyright © 2011-2022 走看看