题解 Seat

传送门

大毒瘤题,本来以为自己看懂了题解能自己写出来,最后还是得靠std

  • 「每次选离其它人距离最远的位置」意味着只能构成log个层,也许可以利用这个性质DP

先扔结论吧:
image
这样的话,层与层之间就(几乎)相互独立了
有了这两个结论,可以考虑分别处理每一层
想知道某一个人选中每一个点的概率
发现这个人在所属的层中,选中奇偶性相同的区间的概率相同
而每一层的区间集合是固定的
那就是要求每个人选中奇/偶区间的概率
发现这个东西并不好求
考虑维护一个辅助DP数组 \(f[i][j]\) 表示到第 \(i\) 个人时,剩余 \(j\) 个偶数区间的概率

  • 当发现一个东西不好直接求/直接DP的时候,考虑设法维护一个辅助数组
    但这个辅助数组不知如何想到

这里特别注意一点,就是用 \(f\) 数组求要求的概率时该除以谁
对应到代码的71~76行的注释
这个地方理解难度不低,建议再康一遍

然后考虑整体求答案
发现每个偶区间都有两种选法
但无论选择哪一个,都会将区间划分成长度为 \(\frac{n}{2}\)\(frac{n}{2}-1\) 的两段,因此这两种选择具有对称性
也就是说,我们可以从下往上统计,每到一个偶区间,就累这个区间左右交换后的贡献(要除以2)
具体康std的注释吧

std的第三次迭代
//注意
//本题中odd为偶数,even为奇数
#include<bits/stdc++.h>
using namespace std;
const int N=1030;
int n,mod;
int qpow(int x,int k,int ans=1){
	while(k){
		if(k&1) ans=ans*x%mod;
		x=x*x%mod;
		k>>=1;
	}
	return ans;
}
//dp为答案
//f为题解中dp数组
int dp[N][N],f[N][N],g[N][N],vis[N],inv[N],cnt[N],odd[N],pos[N];
int main(){
	scanf("%d%d",&n,&mod);
	for(int i=1;i<=n;++i) inv[i]=qpow(i,mod-2);
	vis[0]=vis[n+1]=true;
	for(int i=1;i<=n;++i){
		int pl=0,pr=0,mx;
		for(int j=0;j<=n;++j){
			int r=j+1;
			while(!vis[r]) ++r;
			if(r-j>pr-pl) pl=j,pr=r;
			j=r-1;
		}
		++cnt[mx=(pr-pl)>>1]; odd[mx]+=(pr-pl)&1;
		pos[i]=pl+mx; vis[pl+mx]=true;
		//这种方法保证了在mx相等的时候,人一定先坐偶区间再坐奇区间
		//这个性质为后面限定l~p坐偶区间,p+1~r坐奇区间做了铺垫
	}
	//cnt[i]代表最小距离最大值为i的层中要坐的人数
	//mx的意思是最小距离最大值+1,也即这个最小距离最大值对应的层
	//odd[i]代表最小距离最大值为i的层中包含的长度偶数的区间个数
	//直接模拟坐下过程,每个人在之前基础上选择最靠左的位置坐下,由于定理1的存在,cnt与odd可以得到正确的值
	//pos[k]代表按这种方法每个人最终坐下的位置
	for(int i=1;i<=n;i++)cout<<pos[i]<<" ";puts("");
	int sum=n;
	//sum代表还没有坐下的人数
	for(int i=1;i<=n;++i){
		if(!cnt[i]) continue;//剪枝
		//不存在这个层,一共只有log层
		int l=sum-cnt[i]+1,r=sum;
		//当前这个层要坐cnt[i]个人,l是在这一层坐的最后一个人
		if(i==1) for(int j=l;j<=r;++j) for(int k=l;k<=r;++k) dp[j][pos[k]]=inv[cnt[i]];//
		//到底特判
		//对于每个要在这一层坐下的人,他们所有人的位置都是公共的,因为都在一层里
		//所以每个人他的位置是完全随机的,别人坐的位置他都能坐,概率均等,所以是人数分之一
		else{
			//f[j][k]代表这一层已经坐了j个人,还有k个长度为偶数区间的概率
			for(int j=0;j<=cnt[i];++j) for(int k=0;k<=odd[i];++k) f[j][k]=0;//清空数组
			//memset(f,0,sizeof(f));
			f[0][odd[i]]=1; //还没有坐人,那么该层剩下odd[i]个偶数区间的概率为1
			int p=l+odd[i]-1; //偶数区间长度的最后一个人
			//感性理解为一个分界点,所以可以视为l到p都坐偶数,p到r都坐奇数
			//正确性在于一层之内离最近的人的最大距离固定,况且我们的pos本来就只模拟了多种情况中的一种
			//因此这一层之内的人的顺序本来就是可以变的,所以我们可以对坐在奇区间和偶区间的分开考虑
			for(int j=1;j<=cnt[i];++j){//枚举每个人
				int oddw=0,evenw=0;//odd为偶数 even为奇数
				for(int k=0;k<=odd[i];++k){
					if(!f[j-1][k]) continue;//dp转移 所以f值为0的时候可以剪枝 k表示剩余多少个偶数区间
					int frac=(cnt[i]-(j-1))+k,w=0; //括号内表示剩余的区间个数 +k表示剩余多少个转移点
					//奇区间一个转移点,偶区间两个转移点
					if(k){//还有偶区间剩余
						w=f[j-1][k]*k*2%mod*inv[frac]%mod;//占一个偶区间位置 那么概率为k*2/转移点
						//w对下一个f的贡献,即还剩k个偶数区间时选到下一个偶数区间的概率
						oddw=(oddw+w*inv[odd[i]*2])%mod; //方便累加答案 对于这一次的转移 可能作用在不同的转移点
						//oddw就是对于一个人j他选到每一个偶数区间的概率
						//所有w累加而来得到的是他选到偶数区间的概率,除以总区间数就是选中某一个区间的概率
						//所以注意这里除的是总的区间个数而不是剩余的区间个数
						//具体来说,虽然我们已经选定了一些区间,但固定的只是选中区间的个数,具体选法仍是混沌的
						//而且注意这里所有「选中某个偶数区间的概率」之和是1而不是到这个状态的概率
						//也就是说,我们只考虑要从这一层的区间里选一个
						(f[j][k-1]+=w)%=mod;
					}
					if(cnt[i]-odd[i]){//可以向奇区间转移
						w=f[j-1][k]*(frac-2*k)%mod*inv[frac]%mod;//向奇数区间转移的概率
						evenw=(evenw+w*inv[(cnt[i]+odd[i])-odd[i]*2])%mod;//向不同奇数区间转移
						//这里的w,evenw和上面同理,只不过把偶数换成了奇数
						(f[j][k]+=w)%=mod;
					}
				}
				//f这个dp主要算出了oddw,evenw这个数值,来更新最终答案
				//cout<<(oddw*odd[i]*2%mod+evenw*((cnt[i]+odd[i])-odd[i]*2)%mod)%mod<<endl;可以发现输出这个是1
				//l+j-1代表这个人在所有人之中是第几个
				//对于枚举到的这个人,计算他最后的答案
				//他可能坐在l到r的每个pos位置,因此都要累积
				for(int u=l;u<=p;++u) (dp[l+j-1][pos[u]]+=oddw)%=mod,(dp[l+j-1][pos[u]+1]+=oddw)%=mod;//累加答案
				//统计人坐偶数的答案
				//此时每个人都坐在偶数区间,他既然可以坐在偶数区间的偏左一侧(pos),也一定可以坐在偶数区间的偏右一侧,概率相等
				//对于每个偶数位置的概率都要加上刚才得到的oddw
				for(int u=p+1;u<=r;++u) (dp[l+j-1][pos[u]]+=evenw)%=mod;
				//统计人坐奇数区间的答案,只能坐在中间所以不要加
			}
			//这里已经做完了dp
			//由于钦定了偶数区间坐在左边,那么坐在右边也是一样的答案
			//利用对称性推出偶数区间的答案
			for(int j=l;j<=p;++j){//这些j坐在偶数区间
				int L=pos[j]-i+1,R=pos[j]+i;//当前的偶区间左右端点,i是段长
				//因为他是按着层来的,所以实际上是倒着推的,后面人的概率都已经算过
				for(int v=L;v<=R;++v){
					if(v==pos[j])continue;
					//不能是选择的点
					//这里不加也没有关系,因为当v==pos[j]的时候没有贡献
						  //由于枚举的是下面的点,那么下面的点对于任意j,dp[u][pos[j]]都是0
					for(int u=r+1;u<=n;++u){//后面每一个人
						int s=v<pos[j]?v+i+1:v-i,w=dp[u][v]*inv[2]%mod;//后一个人在位置v的概率除2
						//s找到他对称的点在哪里
						//这里不是简单的对称,因为换了之后左右会互换
						(g[u][v]+=w)%=mod; (g[u][s]+=w)%=mod;//平均一下
						//每个人其实在这一层都有均等的概率坐在偶数区间的靠左和靠右的地方,但是刚才只算了靠左的
						//事实上等概率坐在左侧和右侧,所以要除以二再平均分
					}
				}
				for(int v=L;v<=R;++v) for(int u=r+1;u<=n;++u) dp[u][v]=g[u][v],g[u][v]=0;
			}
		}
		sum-=cnt[i];//考虑下一层 剩余人数减少
	}
	for(int i=1;i<=n;i++,puts("")) for(int j=1;j<=n;j++) printf("%d ",dp[i][j]);
	return 0;
}
我的代码实现
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1050
#define ll long long
#define reg register int
#define fir first
#define sec second
#define make make_pair
//#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, p, mod;
int inv[N*3];
inline void md(int& a, int b) {a+=b; a=a>=mod?a-mod:a;}

namespace force{
	int ans[N][N];
	bool vis[N];
	void dfs(int u, bool* mp, int pro) {
		int dis1[n+2], dis2[n+2]; bool vis[n+2];
		for (reg i=0; i<n+1; ++i) vis[i]=mp[i];
		for (reg i=1,lst=0; i<=n; ++i)
			if (vis[i]) lst=0, dis1[i]=0;
			else dis1[i]=lst++;
		for (reg i=n,lst=0; i; --i)
			if (vis[i]) lst=0, dis2[i]=0;
			else dis2[i]=lst++;
		int maxn=0, cnt=0;
		for (reg i=1; i<=n; ++i) if (!vis[i]) {
			dis1[i]=min(dis1[i], dis2[i]);
			if (dis1[i]>maxn) maxn=dis1[i], cnt=1;
			else if (dis1[i]==maxn) ++cnt;
		}
		for (reg i=1; i<=n; ++i) if (!vis[i] && dis1[i]==maxn) {
			md(ans[u][i], pro*inv[cnt]%p);
			vis[i]=1;
			dfs(u+1, vis, pro*inv[cnt]%p);
			vis[i]=0;
		}
	}
	void solve() {
		dfs(1, vis, 1);
		for (int i=1; i<=n; ++i) {
			for (int j=1; j<=n; ++j)
				printf("%d ", ans[i][j]);
			printf("\n");
		}
		exit(0);
	}
}

namespace task1{
	int mdep, siz[30], dp[30][N][N], f[30][N][2], ans[N][N], tem[N][N], sizp[30], lrge[30], rrge[30]; // 0->even 1->odd
	unordered_map<int, int> mp[30];
	pair<int, int> s[30][5];
	queue< pair<int, int> > q;
	bool vis[30][N][N];
	struct grp{int pos, l, r; bool vis,ntv; inline void build(int a, int b, int c, bool d, bool e){pos=a; l=b; r=c; vis=d; ntv=e;}}g[30][N];
	
	void init(int dep, int l, int r) {
		//cout<<"init: "<<dep<<' '<<l<<' '<<r<<endl;
		if (l>r) return ;
		mdep=max(mdep, dep);
		++mp[dep][r-l+1];
		int mid=(l+r)>>1;
		g[dep][++sizp[dep]].build(mid, l, r, (r-l+1)&1, 0);
		if (l==r) return ;
		init(dep+1, l, mid-1);
		init(dep+1, mid+1, r);
	}
	void dfs(int k, int i, int even, int odd, int pro) {
		//cout<<"dfs "<<k<<' '<<i<<' '<<even<<' '<<odd<<' '<<pro<<endl;
		if (siz[k]==2 && odd && s[k][2].fir-s[k][1].fir==1) {
			md(f[k][i][1], pro*inv[odd]%p);
			dfs(k, i+1, even, odd-1, pro);
		}
		else {
			if (even) {
				md(f[k][i][0], pro*inv[even*2+odd]%p);
				dfs(k, i+1, even-1, odd, pro*2%p*inv[even*2+odd]%p);
			}
			if (odd) {
				md(f[k][i][1], pro*inv[even*2+odd]%p);
				dfs(k, i+1, even, odd-1, pro%p*inv[even*2+odd]%p);
			}
		}
	}
	void solve() {
		init(1, 1, n);
		for (int i=1; i<=mdep; ++i) {
			assert(mp[i].size()<=2);
			for (auto it:mp[i])
				s[i][++siz[i]]=it;
			if (siz[i]==2 && s[i][1].fir&1) swap(s[i][1], s[i][2]);
		}
		int now=1;
		for (int base=1,lst=0,sum=0; sum<n; ++now,lst+=base,sum+=base,base<<=1)
			lrge[now]=lst+1, rrge[now]=lst+base; //, cout<<"for: "<<base<<' '<<lst<<' '<<sum<<endl;
		//cout<<"now: "<<now<<endl;
		//cout<<"r: "<<rrge[now-1]<<endl;
		if (rrge[now-1]==n) ++mdep;
		else rrge[now-2]=n;
		//cout<<"mdep: "<<mdep<<endl;
		//if (mdep==1) mdep=2, lrge[1]=1, rrge[1]=1;
		
		#if 0
		for (int k=1; k<mdep; ++k)
			cout<<"rge: "<<lrge[k]<<' '<<rrge[k]<<endl;
		cout<<endl;
		#endif
		
		#if 0
		for (int k=1; k<mdep; ++k) {
			//cout<<endl;
			//cout<<"k: "<<k<<endl;
			if (siz[k]==1) {
				//cout<<"pos1"<<endl;
				for (int i=1; i<=1<<(k-1); ++i)
					if (s[k][1].fir&1) f[k][i][1]=inv[s[k][1].sec-i+1];
					else f[k][i][0]=inv[(s[k][1].sec-i+1)*2];
			}
			else {
				//cout<<"pos2"<<endl;
				if (s[k][1].fir&1) swap(s[k][1], s[k][2]);
				dp[k][0][s[k][1].sec]=1;
				
				q.push(make(0, s[k][1].sec));
				pair<int, int> u;
				while (q.size()) {
					u=q.front(); q.pop();
					//cout<<"u: "<<u.fir<<' '<<u.sec<<endl;
					int even=u.sec, odd=s[k][2].sec-u.fir+s[k][1].sec-u.sec;
					if (u.fir==1<<(k-1)) continue;
					//cout<<"e&o: "<<even<<' '<<odd<<endl;
					
					if (odd && s[k][2].fir==s[k][1].fir+1) {
						md(dp[k][u.fir+1][u.sec], dp[k][u.fir][u.sec]);
						if (!vis[k][u.fir+1][u.sec]) q.push(make(u.fir+1, u.sec)), vis[k][u.fir+1][u.sec]=1;
					}
					else {
						md(dp[k][u.fir+1][u.sec], dp[k][u.fir][u.sec]*odd*inv[odd+even*2]%p);
						if (!vis[k][u.fir+1][u.sec]) q.push(make(u.fir+1, u.sec)), vis[k][u.fir+1][u.sec]=1;
						if (u.sec<1) continue;
						md(dp[k][u.fir+1][u.sec-1], dp[k][u.fir][u.sec]*even*2*inv[odd+even*2]%p);
						if (!vis[k][u.fir+1][u.sec-1]) q.push(make(u.fir+1, u.sec-1)), vis[k][u.fir+1][u.sec-1]=1;
					}
				}
				
				for (int i=0; i<1<<(k-1); ++i)
					for (int j=0; j<=s[k][1].sec; ++j) {
						int even=j, odd=s[k][2].sec-i+s[k][1].sec-j;
						//cout<<"ij: "<<i<<' '<<j<<endl;
						//cout<<"e&o2: "<<even<<' '<<odd<<endl;
						if (siz[k]==2 && odd && s[k][2].fir==s[k][1].fir+1) 
							md(f[k][i+1][1], dp[k][i][j]*inv[odd]%p);
						else {
							if (even) md(f[k][i+1][0], dp[k][i][j]*inv[odd+even*2]%p);
							if (odd) md(f[k][i+1][1], dp[k][i][j]*inv[odd+even*2]%p);
						}
					}
					
			}
		}
		#else
		for (int k=1; k<mdep; ++k)
			if (siz[k]==2) dfs(k, 1, s[k][1].sec, s[k][2].sec, 1);
			else if (s[k][1].fir&1) dfs(k, 1, 0, s[k][1].sec, 1);
			else dfs(k, 1, s[k][1].sec, 0, 1);
		#endif
		
		#if 0
		cout<<"inv: "; for (int i=1; i<=n; ++i) cout<<inv[i]<<' '; cout<<endl;
		#endif
		
		#if 0
		for (int k=1; k<=mdep; ++k) {
			for (int j=1; j<=siz[k]; ++j)
				cout<<s[k][j].fir<<','<<s[k][j].sec<<' ';
			cout<<endl;
		} cout<<endl;
		#endif
		
		#if 0
		for (int k=1; k<mdep; ++k)
			for (int i=0; i<=1<<(k-1); ++i)
				for (int j=0; j<=n; ++j)
					printf("dp[%d][%d][%d]=%d\n", k, i, j, dp[k][i][j]);
		cout<<endl;
		#endif
		
		#if 0
		for (int k=1; k<mdep; ++k)
			for (int i=1; i<=1<<(k-1); ++i)
				printf("f[%d][%d][0]=%d f[%d][%d][1]=%d\n", k, i, f[k][i][0], k, i, f[k][i][1]);
		cout<<endl;
		#endif
		
		#if 0
		for (int k=1; k<mdep; ++k) {
			cout<<"k: "<<k<<endl;
			for (int i=1; i<=sizp[k]; ++i)
				cout<<g[k][i].pos<<' '<<g[k][i].l<<' '<<g[k][i].r<<' '<<g[k][i].vis<<endl;
		} cout<<endl;
		#endif
		
		int avl=0, newl=lrge[mdep-1];
		for (int i=1; i<=sizp[mdep-1]; ++i) avl+=g[mdep-1][i].r-g[mdep-1][i].l+1;
		if (siz[mdep-1]==2 && s[mdep-1][2].fir==s[mdep-1][1].fir+1) {
			for (int t=1; t<=sizp[mdep-1]; ++t)
				for (int i=1; i<=s[mdep-1][2].sec; ++i)
					for (int j=g[mdep-1][t].l; j<=g[mdep-1][t].r; ++j) if (g[mdep-1][t].vis) {
						ans[lrge[mdep-1]+i-1][g[mdep-1][t].pos]=f[mdep-1][i][1];
						g[mdep-1][t].ntv=1;
					}
			newl+=s[mdep-1][2].sec;
			avl-=s[mdep-1][2].sec;
		}
		for (int i=newl; i<=rrge[mdep-1]; ++i)
			for (int j=1; j<=sizp[mdep-1]; ++j)
				for (int k=g[mdep-1][j].l; k<=g[mdep-1][j].r; ++k)
					ans[i][k]=inv[avl];
		for (int k=mdep-2; k>0; --k) {
			//cout<<"K: "<<k<<endl;
			for (int t=1; t<=sizp[k]; ++t)
				for (int i=1; i<=1<<(k-1); ++i)
					for (int j=g[k][t].l; j<=g[k][t].r; ++j)
						if (g[k][t].vis) ans[lrge[k]+i-1][g[k][t].pos]=f[k][i][1];
						else {
							ans[lrge[k]+i-1][g[k][t].pos]=f[k][i][0];
							ans[lrge[k]+i-1][g[k][t].pos+1]=f[k][i][0];
						}
			for (int t=1; t<=sizp[k]; ++t) if (!g[k][t].vis && !g[k][t].ntv) {
				for (int i=lrge[k+1]; i<=n; ++i) {
					for (int j=g[k][t].l; j<=g[k][t].r; ++j)
						ans[i][j]=ans[i][j]*inv[2]%p;
					/* 
					for (int j=g[k][t].pos+1; j<=g[k][t].r; ++j)
						tem[i][j]=ans[i][j];
					for (int j=g[k][t].l; j<g[k][t].pos; ++j)
						md(ans[i][g[k][t].pos+2+j-g[k][t].l], ans[i][j]);
					for (int j=g[k][t].pos+1; j<=g[k][t].r; ++j)
						md(ans[i][g[k][t].l+j-g[k][t].pos-1], tem[i][j]);
					*/
				}
			}
		}
		for (int i=1; i<=n; ++i) {
			for (int j=1; j<=n; ++j)
				printf("%d ", ans[i][j]);
			printf("\n");
		}
	}
}

namespace task{
	int pos[N], cnt[N], ecnt[N], dp[N][N], f[N][N], tem[N][N], evenw[N], oddw[N];
	queue< pair<int, int> > q;
	bool vis[N], vis2[N][N];
	void solve() {
		vis[0]=vis[n+1]=1;
		for (int i=1; i<=n; ++i) {
			int pl=0, pr=0, maxn;
			for (int j=0,r; j<=n; ++j) {
				r=j+1;
				while (!vis[r]) ++r;
				if (r-j>pr-pl) pl=j, pr=r;
				j=r-1;
			}
			++cnt[maxn=(pr-pl)>>1];
			ecnt[maxn]+=(pr-pl)&1;
			pos[i]=pl+maxn;
			vis[pl+maxn]=1;
		}
		//cout<<"pos: "; for (int i=1; i<=n; ++i) cout<<pos[i]<<' '; cout<<endl;
		int sum=n;
		for (int k=1,l,r,p; k<=n; ++k) if (cnt[k]) {
			//cout<<"k: "<<k<<endl;
			l=sum-cnt[k]+1; r=sum; p=l+ecnt[k]-1; sum-=cnt[k];
			//cout<<"lr: "<<l<<' '<<r<<endl;
			//cout<<"cnt: "<<cnt[k]<<' '<<ecnt[k]<<endl;
			if (k==1) {
				for (int i=l; i<=r; ++i) for (int j=l; j<=r; ++j) dp[i][pos[j]]=inv[cnt[k]];
				//for (int i=1; i<=n; ++i) {for (int j=1; j<=n; ++j) printf("%d ", dp[i][j]); printf("\n");}
				continue;
			}
			//for (reg i=0; i<=cnt[k]; ++i) for (reg j=0; j<=ecnt[k]; ++j) f[i][j]=0, vis2[i][j]=0;
			//for (reg i=0; i<=cnt[k]; ++i) evenw[i]=oddw[i]=0;
			memset(f, 0, sizeof(f)); memset(vis2, 0, sizeof(vis2)); memset(evenw, 0, sizeof(evenw)); memset(oddw, 0, sizeof(oddw));
			f[0][ecnt[k]]=1;
			q.push(make(0, ecnt[k]));
			pair<int, int> u;
			while (q.size()) {
				u=q.front(); q.pop();
				if (!f[u.fir][u.sec]) continue;
				int odd=cnt[k]-u.fir-u.sec, even=u.sec, w;
				if (even) {
					w=f[u.fir][u.sec]*even*2%mod*inv[odd+even*2]%mod;
					md(evenw[u.fir+1], w*inv[ecnt[k]*2]%mod);
					md(f[u.fir+1][u.sec-1], w);
					if (!vis2[u.fir+1][u.sec-1]) q.push(make(u.fir+1, u.sec-1)), vis2[u.fir+1][u.sec-1]=1;
				}
				if (cnt[k]-ecnt[k]) {
					w=f[u.fir][u.sec]*odd%mod*inv[odd+even*2]%mod;
					md(oddw[u.fir+1], w*inv[cnt[k]-ecnt[k]]%mod);
					md(f[u.fir+1][u.sec], w);
					if (!vis2[u.fir+1][u.sec]) q.push(make(u.fir+1, u.sec)), vis2[u.fir+1][u.sec]=1;
				}
			}
			//for (int i=1; i<=cnt[k]; ++i) cout<<oddw[i]<<' '<<evenw[i]<<endl;
			for (int i=1; i<=cnt[k]; ++i) for (int j=l; j<=p; ++j) dp[l+i-1][pos[j]]=dp[l+i-1][pos[j]+1]=evenw[i];
			for (int i=1; i<=cnt[k]; ++i) for (int j=p+1; j<=r; ++j) dp[l+i-1][pos[j]]=oddw[i];
			#if 1
			for (int i=l; i<=p; ++i) {
				int ls=pos[i]-k+1, rs=pos[i]+k;
				for (int j=r+1; j<=n; ++j) {
					for (int q=ls; q<=rs; ++q)
						dp[j][q]=dp[j][q]*inv[2]%mod;
					for (int q=ls; q<=rs; ++q)
						tem[j][q]=dp[j][q];
					for (int q=ls; q<pos[i]; ++q)
						md(dp[j][pos[i]+2+q-ls], dp[j][q]);
					for (int q=pos[i]+1; q<=rs; ++q)
						md(dp[j][ls+q-pos[i]-1], tem[j][q]);
				}
			}
			#endif
		}
		for (int i=1; i<=n; ++i) {
			for (int j=1; j<=n; ++j)
				printf("%d ", dp[i][j]);
			printf("\n");
		}
		exit(0);
	}
}

signed main()
{
	n=read(); p=read(); mod=p;
	inv[0]=inv[1]=1;
	for (reg i=2; i<=n*3; ++i) inv[i]=(p-p/i)*inv[p%i]%p;
	//force::solve();
	task::solve();
	
	return 0;
}
posted @ 2021-09-11 18:58  Administrator-09  阅读(14)  评论(0编辑  收藏  举报