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);
}