arc113F Social Distance

31 篇文章 0 订阅
9 篇文章 0 订阅

Description

Solution

  • 考虑将恰好转化为至少,即两两距离不小于z的概率,这是一个函数 f ( z ) f(z) f(z),之后只要对 f ( z ) f(z) f(z)进行积分之后恰好就是答案了。
  • 对于一个固定的 z z z,我们可以将模型转换一下,第 i i i个人对应的区间变为 [ x i − 1 − ( i − 1 ) z , x i − ( i − 1 ) z ] [x_{i-1}-(i-1)z,x_i-(i-1)z] [xi1(i1)z,xi(i1)z],那么两两之间距离不超过 z z z等价于在这个新的区间随机,最后 n n n个人单调递增。
  • 将这些区间没有用的部分除去,然后可以通过一个简单的DP求出期望函数,即设 F [ i ] [ j ] F[i][j] F[i][j]表示到了第 i i i个端点,前面已经有 1 1 1 j j j完成,枚举当前区间出现 j + 1 j+1 j+1 k k k,里面是一个 n n n次的多项式。转移可以做到 n 4 n^4 n4
  • 然后预处理 n 2 n^2 n2个节点大小关系交替的时刻,看作分段函数,对于每一段分别DP,分别积分即可。
  • O ( n 6 ) O(n^6) O(n6)
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define maxn 22
#define db double
#define ll long long 
#define mo 998244353
using namespace std;

int n,i,j,k,x[maxn],L[maxn],R[maxn],tot,p[maxn*2],l[maxn],r[maxn],id0[maxn*2],id1[maxn*2];
struct arr{int x,y; ll p,q;} a[maxn*maxn*4];
int cmp(arr a,arr b){return a.p*b.q<b.p*a.q;}
ll ans,f[maxn][maxn],g[maxn],invf[maxn];

ll ksm(ll x,ll y){
	ll s=1;
	for(;y;y/=2,x=x*x%mo) if (y&1)
		s=s*x%mo;
	return s;
}
int X(int x){return (x>n)?R[x-n]:L[x];}
int I(int x){return (x>n)?x-n:x;}

int main(){
	freopen("ceshi.in","r",stdin);
	scanf("%d",&n);
	invf[0]=1;for(i=1;i<=n;i++) invf[i]=invf[i-1]*ksm(i,mo-2)%mo;
	for(i=0;i<=n;i++) scanf("%d",&x[i]);
	for(i=1;i<=n;i++) L[i]=x[i-1],R[i]=x[i];
	for(i=1;i<=n;i++) for(j=1;j<i;j++) for(int t1=0;t1<2;t1++) for(int t2=0;t2<2;t2++)
		tot++,a[tot].x=j+t1*n,a[tot].y=i+t2*n,a[tot].p=(t2?R[i]:L[i])-(t1?R[j]:L[j]),a[tot].q=i-j;
	sort(a+1,a+1+tot,cmp);
	for(i=1;i<=n;i++) p[++p[0]]=i,p[++p[0]]=i+n;
	for(int now=1;now<tot;now++){
		int Tp=0;
		for(i=1;i<=n*2;i++) if (p[i]==a[now].y){
			for(j=i+1;j<=n*2;j++) if (p[j]==a[now].x) Tp=1;
			if (Tp) break;
			for(j=i;j<n*2;j++) p[j]=p[j+1];
			break;
		}
		if (!Tp)
			for(i=1;i<n*2;i++) if (p[i]==a[now].x){
				for(j=n*2;j>i;j--) p[j]=p[j-1];
				p[i]=a[now].y; break;
			}
		if (a[now].p*a[now+1].q==a[now+1].p*a[now].q) continue;
		for(i=1;i<=n*2;i++) if (p[i]<=n) l[p[i]]=i; else r[p[i]-n]=i;
		for(i=2;i<=n;i++) l[i]=max(l[i],l[i-1]);
		for(i=n-1;i>=1;i--) r[i]=min(r[i],r[i+1]);
		int tp=1;
		for(i=1;i<=n;i++) if (l[i]>=r[i]) {tp=0;break;}
		if (!tp) break;
		memset(id0,0,sizeof(id0)),memset(id1,0,sizeof(id1));
		for(i=1;i<=n;i++) id0[l[i]]=max(id0[l[i]],i),id1[r[i]]=max(id1[r[i]],i);
		memset(f,0,sizeof(f)),f[0][0]=1;
		int st=1,ed=0;
		for(i=1;i<2*n;i++) {
			ed=max(ed,id0[i]),st=max(st,id1[i]+1);
			if (ed<st) continue;
			for(j=ed-1;j>=st-1;j--) {
				memcpy(g,f[j],sizeof(g));
				ll v=X(p[i+1])-X(p[i]),u=-(I(p[i+1])-I(p[i]));
				for(k=1;k<=ed-j;k++){
					for(int t=j+k;t;t--)
						g[t]=(g[t]*v+g[t-1]*u)%mo;
					g[0]=g[0]*v%mo;
					for(int t=0;t<=j+k;t++)
						(f[j+k][t]+=g[t]*invf[k])%=mo;
				}
			}
		}
		ll X=a[now].p*ksm(a[now].q,mo-2)%mo;
		ll Y=a[now+1].p*ksm(a[now+1].q,mo-2)%mo;
		for(i=0;i<=n;i++)
			ans+=f[n][i]*ksm(i+1,mo-2)%mo*(ksm(Y,i+1)-ksm(X,i+1))%mo;
		ans%=mo;
	}
	for(i=1;i<=n;i++) ans=ans*ksm(x[i]-x[i-1],mo-2)%mo;
	printf("%lld\n",(ans%mo+mo)%mo);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ARC069 F 题目传送门:https://atcoder.jp/contests/arc069/tasks/arc069_d 题目描述: 给定两个长度为 $n$ 的字符串 $s$ 和 $t$,每个字符都是小写字母。你需要找到一个长度为 $n$ 的字符串 $u$,满足: - 对于所有 $i \in [1,n]$,都有 $u_i \in \{s_i,t_i\}$。 - 对于所有 $i \in [1,n-1]$,都有 $u_i \neq u_{i+1}$。 - 对于所有 $i \in [1,n-2]$,都有 $u_i \neq u_{i+2}$。 求满足条件的字符串 $u$ 的个数,对 $10^9+7$ 取模。 解题思路: 这是一道比较经典的字符串构造问题,可以用 dp 或者数学方法来解决。 方法一:dp 我们可以使用 dp 来解决这个问题。设 $f_{i,j,k}$ 表示构造了前 $i$ 个字符,第 $i$ 个字符为 $j$,且第 $i-1$ 个字符为 $k$ 的方案数。其中,$j \in \{s_i,t_i\}$,$k \in \{s_{i-1},t_{i-1}\}$。 状态转移方程如下: $$f_{i,j,k} = \sum\limits_{l \in \{s_{i-2},t_{i-2}\},l \neq j} f_{i-1,k,l}$$ 最终的答案为 $\sum\limits_{j \in \{s_n,t_n\}} \sum\limits_{k \in \{s_{n-1},t_{n-1}\}} f_{n,j,k}$。 时间复杂度为 $O(n)$。 方法二:数学 我们可以定义 $a_i$ 表示以 $s_i$ 结尾,且不存在相邻字符相等的字符串的方案数;$b_i$ 表示以 $s_i$ 结尾,且存在相邻字符相等的字符串的方案数;$c_i$ 表示以 $t_i$ 结尾,且不存在相邻字符相等的字符串的方案数;$d_i$ 表示以 $t_i$ 结尾,且存在相邻字符相等的字符串的方案数。 根据题目的限制条件,我们可以得到递推式: $$\begin{cases} a_{i+1} = 2(b_i+c_i+d_i) \\ b_{i+1} = a_i \\ c_{i+1} = 2(a_i+d_i) \\ d_{i+1} = b_i \end{cases}$$ 初始状态为 $a_1=1,b_1=0,c_1=1,d_1=1$。 最终的答案为 $a_n+c_n$。 时间复杂度为 $O(n)$。 代码实现:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值