其他分享
首页 > 其他分享> > topcoder 8785 PSequence

topcoder 8785 PSequence

作者:互联网

给出一个包含 \(n\) 个数的集合 \(S\) 和一个正整数 \(p\) ,求能组成多少种不同的序列,满足以下条件:

  1. \(S\) 中的元素都恰好包含一次.
  2. 序列中相邻两位\(s_2-s_1\) 不能被 \(p\) 整除.

模 \(10^9+7\).

\(1\leq n\leq 30,1\leq p\leq 1000\)

和 atcdoer tdpc o 题文字列超级像.

考虑按 \(s_i\) 的模数分类,相同一类不能相邻,那么一类一类地考虑 .

令 \(cnt(i)\) 统计 \(\%p\) 余 \(i\) 的个数有 \(cnt(i)\) ,令 \(sum(i)=\sum\limits^i cnt(j)\)

用 \(dp(i,j)\) 表示考虑到 \(\%p\) 余 \(i\) 的数,有 \(j\) 个相同相邻位子的方案数.

考虑模数为 \(i+1\) 的数.

首先,令 \(cnt(i+1)\) 个数分成了 \(k\) 段,其中 \(x\) 段放在了相同相邻位子的中间,那么,剩下 \(k-x\) 个就要放在 \(m+1-j\) 个位置上,此时,相同相邻位子的个数就是 \(cnt(i+1)-k+j-x\) .

\(dp\) 转移方程为

\(cnt(i+1)!\dbinom{cnt(i+1)-1}{k-1}\dbinom{k}{x}\dbinom{m+1-j}{k-x}dp(i,j)\ \longrightarrow\ dp(i+1,cnt(i+1)-k+j-x)\)

时间复杂度 : \(O(n^4)\)

空间复杂度 : \(O(np)\)

code

#include<bits/stdc++.h>
using namespace std;
const long long mod=1234567891;
long long dp[1010][50];
long long C[50][50],P[50];
class PSequence{
public:
	int n;
	int cnt[1010];
	inline void upd(long long &x,long long y){x=(x+y)%mod;}
	int count(vector<int>a,int p){
		n=(int)a.size();
		for(int i=0;i<n;i++)a[i]=(a[i]%p+p)%p;
		for(int i=0;i<n;i++)cnt[a[i]]++;
		P[0]=1;
		for(int i=1;i<50;i++)P[i]=1ll*P[i-1]*i%mod;
		C[0][0]=1;
		for(int i=1;i<50;i++){
			C[i][0]=1;
			for(int j=1;j<=i;j++){
				upd(C[i][j],C[i-1][j-1]);
				upd(C[i][j],C[i-1][j]);
			}
		}
		dp[0][max(cnt[0]-1,0)]=P[cnt[0]];
		int m=cnt[0];
		for(int i=0;i+1<p;i++){
			if(cnt[i+1]==0){
				for(int j=0;j<=m;j++){
					upd(dp[i+1][j],dp[i][j]);
				}
			}
			else{
				for(int j=0;j<=m;j++){
					if(dp[i][j]==0)continue;
					for(int k=1;k<=cnt[i+1];k++)for(int x=0;x<=k;x++){
						if(m-j+1<k-x||j+cnt[i+1]-k-x<0)continue;
						long long tmp=1ll*P[cnt[i+1]]*C[cnt[i+1]-1][k-1]%mod;
						tmp=1ll*tmp*C[j][x]%mod;
						tmp=1ll*tmp*C[m-j+1][k-x]%mod;
						upd(dp[i+1][j+cnt[i+1]-k-x],1ll*dp[i][j]*tmp%mod);
					}	
				}
			}
			m+=cnt[i+1];
		}
		return dp[p-1][0];
	}
};

标签:cnt,int,50,long,leq,dp,PSequence,topcoder,8785
来源: https://www.cnblogs.com/suadwm/p/15031681.html