题解 客星璀璨之夜

传送门

并不知道小球进洞模型是什么,并且不建议在机房百度它

  • 所以……天体湮灭模型(雾):一个更广为人知(?)的名字是小球进洞模型
    考虑只有一个球,两个洞的情况:显然向两边滚的概率各是 \(\frac{1}{2}\)
    考虑拓展到两个球:发现其中一个球在滚动湮灭后会变成情况1,然后就可以转移了
    我们枚举这一轮选了哪个球及它往哪边滚
    由于我们已经知道它湮灭后形成的更长间隔期望经过多少次了
    则这段间距的期望经过次数就是更长间隔期望经过次数加上这次选中它并向这边滚的概率

发现有很多重复的转移,打表找个规律可以优化掉一维,复杂度 \(O(n^2)\)

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 3010
#define ll long long 
//#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
ll x[N<<1], dp[N][N<<1], inv[N<<1];
const ll p=998244353;

signed main()
{
	n=read();
	inv[0]=inv[1]=1;
	for (int i=2; i<=n*2+1; ++i) inv[i]=(p-p/i)*inv[p%i]%p;
	for (int i=1; i<=n*2+1; ++i) x[i]=read();
	dp[1][1]=dp[1][2]=inv[2];
	for (int i=2; i<=n; ++i) {
		for (int j=1; j<=2*i; ++j) {
			dp[i][j] = (dp[i][j]+(j-1)*dp[i-1][j-2]%p*inv[i*2]%p)%p;
			//if (i==10 && j==2) printf("dp[%d][%d]+=%d*dp[%d][%d]*inv[i*2]\n", i, j, (j-1), i-1, j-2);
			dp[i][j] = (dp[i][j]+dp[i-1][j-1]*inv[i*2]+inv[i*2])%p;
			dp[i][j] = (dp[i][j]+(2*i-j)*dp[i-1][j]%p*inv[i*2]%p)%p;
			//if (i==10 && j==2) printf("dp[%d][%d]+=%d*dp[%d][%d]*inv[i*2]\n", i, j, (2*i-j), i-1, j);
		}
		#if 0
		for (int j=1; j<=i; ++j) {
			dp[i][j*2]=(dp[i][j*2]+inv[i*2])%p;
			dp[i][j*2-1]=(dp[i][j*2-1]+inv[i*2])%p;
			//if (i==10) printf("dp[%d][%d]+=inv[2]\n", i, j*2);
			//if (i==10) printf("dp[%d][%d]+=inv[2]\n", i, j*2-1);
			int pos1=0, pos2=0;
			for (int k=1; k<=2*i; ++k) {
				if (k<=2*j-2 || k>=2*j+1) ++pos1;
				dp[i][k] = (dp[i][k]+dp[i-1][pos1]*inv[i*2]%p)%p;
				if (i==10 && k==2) printf("dp[%d][%d]+=dp[%d][%d]*inv[i*2]\n", i, k, i-1, pos1);
				if (k<=2*j-1 || k>=2*j+2) ++pos2;
				dp[i][k] = (dp[i][k]+dp[i-1][pos2]*inv[i*2]%p)%p;
				if (i==10 && k==2) printf("dp[%d][%d]+=dp[%d][%d]*inv[i*2]\n", i, k, i-1, pos2);
			}
		}
		#endif
		//for (int j=1; j<=i*2; ++j) printf("cnt[%d][%d]=%lld\n", i-1, j, cnt[i][j]);
	}
	ll ans=0;
	for (int i=1; i<=2*n; ++i) ans=(ans+dp[n][i]*((x[i+1]-x[i])%p)%p)%p;
	printf("%lld\n", ans);
	
	return 0;
}
上一篇:C++分割字符串方法


下一篇:题解 序列问题