• 联考20200726 T1 钩子




    分析:
    我们发现每个人操作时,不管前面的人怎么挂,当前这个人的\(d\)为定值
    那么我们可以尝试以某种特定的方案模拟整个过程,再通过一些变换求出概率
    假设目前的最大距离为\(d\),可以挂的空位置有\(m\)段,说明从这个人开始的后\(m\)个人都是这个\(d\),他们的概率可以一起算
    \(m\)段的长度有奇数和偶数,奇数时可以直接挂在中点,偶数时中间两个点都可以挂
    假设p段奇数,q段偶数,我们可以列出DP式\(f_{i,j,k}\)表示第\(i\)个人要挂奇数段时,奇数段剩\(j\)个,偶数段剩\(k\)个的概率
    由于\(i+j+k=m\)\(i\)可以省去
    用一个奇数段的概率为\(\frac{j}{j+2k}\),偶数段为\(\frac{2k}{j+2k}\)
    表示第\(i\)个人要挂偶数段时,设一个DP式\(g_{i,j}\)同样处理
    复杂度为\(O(n^2)\)
    但是一个人选择挂偶数段时,两个点各自会产生新的情况,但是我们发现在这一段当中,挂左边和挂右边产生的情况是一一对称的
    我们强行确定挂左边,并在中间记录一个对称轴,全部处理完之后,对称的位置取一次平均数就好了
    特别注意,当最后\(d=1\)时,剩下的位置都可以选并且互不影响,不要进行上面的DP,直接暴力处理并结束就好了
    复杂度式子冗杂,但整体上是不超过\(O(n^2)\)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<iostream>
    #include<map>
    #include<string>
    
    #define maxn 1005
    
    using namespace std;
    
    inline int getint()
    {
    	int num=0,flag=1;char c;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    	return num*flag;
    }
    
    int n,MOD;
    int P[maxn],cur;
    int vis[maxn];
    int T[maxn*maxn],L[maxn*maxn],M[maxn*maxn],R[maxn*maxn],cnt;
    int ans[maxn][maxn];
    int f[maxn][maxn],g[maxn][maxn];
    int inv[maxn];
    
    inline int ksm(int num,int k)
    {
    	int ret=1;
    	for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD;
    	return ret;
    }
    
    int main()
    {
    	n=getint(),MOD=getint();inv[0]=1;
    	for(int i=1;i<=n;i++)inv[i]=ksm(i,MOD-2);
    	for(int t=1;t<=n;t++)
    	{
    		P[cur=0]=0;
    		for(int i=1;i<=n;i++)if(vis[i])P[++cur]=i;
    		P[++cur]=n+1;
    		int mx=0,tim=0,tot[2]={0};
    		for(int i=cur;i;i--)P[i]=P[i]-P[i-1];
    		for(int i=1;i<=cur;i++)
    			if(P[i]/2>mx)mx=P[i]/2,tim=1+(P[i]&1),tot[0]=tot[1]=0,tot[P[i]&1]++;
    			else if(P[i]/2==mx)tim+=1+(P[i]&1),tot[P[i]&1]++;
    		int p=ksm(tim,MOD-2);
    		if(mx==1)
    		{
    			for(int i=1;i<=n;i++)if(!vis[i])ans[t][i]=p;
    			continue;
    		}
    		for(int i=0;i<=tot[0];i++)for(int j=0;j<=tot[1];j++)f[i][j]=g[i][j]=0;
    		f[0][0]=g[0][0]=1;
    		for(int tt=0;tt<tot[0]+tot[1];tt++)
    		{
    			int sumf=0,sumg=0;
    			for(int i=max(0,tt-tot[1]);i<=min(tt,tot[0]);i++)
    			{
    				int j=tt-i,num=tot[0]-i+2*(tot[1]-j);
    				sumf=(sumf+1ll*f[i][j]*inv[num])%MOD;
    				sumg=(sumg+1ll*g[i][j]*inv[num])%MOD;
    				if(i<tot[0])
    					f[i+1][j]=(f[i+1][j]+1ll*f[i][j]*(tot[0]-i-1)%MOD*inv[num])%MOD,
    					g[i+1][j]=(g[i+1][j]+1ll*g[i][j]*(tot[0]-i)%MOD*inv[num])%MOD;
    				if(j<tot[1])
    					f[i][j+1]=(f[i][j+1]+1ll*f[i][j]*2*(tot[1]-j)%MOD*inv[num])%MOD,
    					g[i][j+1]=(g[i][j+1]+1ll*g[i][j]*2*(tot[1]-j-1)%MOD*inv[num])%MOD;
    			}
    			int now=0;
    			for(int i=1;i<=cur;now+=P[i++])if(P[i]/2==mx)
    			{
    				if(P[i]&1)
    				{
    					ans[t+tt][now+mx]=ans[t+tt][now+mx+1]=sumg;
    					T[++cnt]=t+1,L[cnt]=now+1,M[cnt]=now+mx,R[cnt]=now+P[i]-1;
    				}
    				else ans[t+tt][now+mx]=sumf;
    				vis[now+mx]=1;
    			}
    		}
    		t+=tot[0]+tot[1]-1;
    	}
    	for(int i=cnt;i;i--)
    	{
    		for(int j=T[i];j<=n;j++)for(int k=L[i];k<=M[i];k++)
    			ans[j][k]=ans[j][R[i]+L[i]-k]=1ll*(ans[j][k]+ans[j][R[i]+L[i]-k])*inv[2]%MOD;
    	}
    	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)printf("%d%c",ans[i][j],j==n?'\n':' ');
    }
    

  • 相关阅读:
    Python 强制停止多线程运行
    自动化测试 Appium之Python运行环境搭建 Part2
    自动化测试 Appium之Python运行环境搭建 Part1
    Genymotion Android模拟器Genymotion的安装和使用
    Easyui datagrid combobox输入框下拉(取消)选值和编辑已选值处理
    性能测试 接口性能测试需要注意的点
    Python 基于Python及zookeeper实现简单分布式任务调度系统设计思路及核心代码实现
    lintcode:整数排序||
    lintcode:整数排序
    lintcode:玩具工厂
  • 原文地址:https://www.cnblogs.com/IzayoiDoyo/p/13385759.html
Copyright © 2020-2023  润新知