A. Reverse
B. Silhouette
C. Seat
1 //注意 因为出题人过于弱智 2 //本题中odd为偶数,even为奇数 3 #include<bits/stdc++.h> 4 using namespace std; 5 const int N=1030; 6 int n,mod; 7 int qpow(int x,int k,int ans=1){ 8 while(k){ 9 if(k&1) ans=ans*x%mod; 10 x=x*x%mod; 11 k>>=1; 12 } 13 return ans; 14 } 15 //dp为答案 16 //f为题解中dp数组 17 int dp[N][N],f[N][N],g[N][N],vis[N],inv[N],cnt[N],odd[N],pos[N]; 18 int main(){ 19 scanf("%d%d",&n,&mod); 20 for(int i=1;i<=n;++i) inv[i]=qpow(i,mod-2); 21 vis[0]=vis[n+1]=true; 22 for(int i=1;i<=n;++i){ 23 int pl=0,pr=0,mx; 24 for(int j=0;j<=n;++j){ 25 int r=j+1; 26 while(!vis[r]) ++r; 27 if(r-j>pr-pl) pl=j,pr=r; 28 j=r-1; 29 } 30 ++cnt[mx=pr-pl>>1]; odd[mx]+=pr-pl&1; 31 pos[i]=pl+mx; vis[pl+mx]=true; 32 } 33 int sum=n; 34 for(int i=1;i<=n;++i){ 35 if(!cnt[i]) continue; 36 int l=sum-cnt[i]+1,r=sum; 37 if(i==1) for(int j=l;j<=r;++j) for(int k=l;k<=r;++k) dp[j][pos[k]]=inv[cnt[i]];//直接赋值为距离为1个数的逆元? 或许这里也被平均掉了 38 else{ 39 for(int j=0;j<=cnt[i];++j) for(int k=0;k<=odd[i];++k) f[j][k]=0;//清空数组 40 f[0][odd[i]]=1; //还没有坐人,那么该层剩下odd[i]个偶数区间的概率为1 41 int p=l+odd[i]-1; //偶数区间长度的最后一个人 42 for(int j=1;j<=cnt[i];++j){ 43 int oddw=0,evenw=0;//odd为偶数 even为奇数 44 for(int k=0;k<=odd[i];++k){ 45 if(!f[j-1][k]) continue;//dp转移 所以f值为0的时候可以剪枝 k表示剩余多少个偶数区间 46 int frac=(cnt[i]-(j-1))+k,w=0; //括号内表示剩余的区间个数 +k表示剩余多少个转移点 47 if(k){//还有偶区间剩余 48 w=f[j-1][k]*k*2%mod*inv[frac]%mod;//占一个偶区间位置 那么概率为k*2/转移点 49 oddw=(oddw+w*inv[odd[i]*2])%mod; //方便累加答案 对于这一次的转移 可能作用在不同的转移点 50 (f[j][k-1]+=w)%=mod; 51 } 52 if(cnt[i]-odd[i]){//可以向奇区间转移 53 w=f[j-1][k]*(frac-2*k)%mod*inv[frac]%mod;//向奇数区间转移的概率 54 evenw=(evenw+w*inv[(cnt[i]+odd[i])-odd[i]*2])%mod;//向不同奇数区间转移 55 (f[j][k]+=w)%=mod; 56 } 57 } 58 for(int u=l;u<=p;++u) (dp[l+j-1][pos[u]]+=oddw)%=mod,(dp[l+j-1][pos[u]+1]+=oddw)%=mod;//累加答案 59 for(int u=p+1;u<=r;++u) (dp[l+j-1][pos[u]]+=evenw)%=mod;//这里存在疑问 似乎将偶数区间默认加给了前面的pos 60 } 61 for(int j=l;j<=p;++j){//偶 62 int L=pos[j]-i+1,R=pos[j]+i;//当前的偶区间左右端点 63 for(int v=L;v<=R;++v){ 64 if(v==pos[j]) continue;//不能是选择的点 65 for(int u=r+1;u<=n;++u){//后面每一个人 66 int s=v<pos[j]?v+i+1:v-i,w=dp[u][v]*inv[2]%mod;//后一个人在位置v的概率除2 67 (g[u][v]+=w)%=mod; (g[u][s]+=w)%=mod;//平均一下 虽然不知道为啥 但是感觉很对 68 } 69 } 70 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; 71 } 72 } 73 sum-=cnt[i];//考虑下一层 剩余人数减少 74 } 75 for(int i=1;i<=n;i++,puts("")) for(int j=1;j<=n;j++) printf("%d ",dp[i][j]); 76 return 0; 77 }skyh倾情注释压行版std