CF1286D LCC

一、题目

点此看题

二、解法

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

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

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

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

\[f[i][1]\leftarrow p[i]\times(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])\times(f[i-1][1]\cdot l_i[0][0]+f[i-1][1]\cdot l_i[1][0]) \]

上面的转移很容易写成矩阵的形式,具体实现就是把每种碰撞组合排序,然后做动态 \(dp\) 即可,时间复杂度 \(O(n\log 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\n",ans);
}
posted @ 2021-09-06 16:42  C202044zxy  阅读(32)  评论(0编辑  收藏  举报