P14836

厉害。

分开算一种分配方案的满意度和分配物品的方案数。

排序,形成若干个相等连续段,表示为长 。对一个 的大小关系算满意度:设 表示当前已经加入 这些人,形成长 的大小关系 ,每次枚举 的一个超集作为新的一个相等连续段,贡献可以在外面 算。对于 个长为 ,有 个超集,总复杂度

对于 ,方案数是 不为 的充要条件是 在每个 进制位上都没有进位。那就按 进制表示从大到小,设 表示已经考虑了 位,目前大小关系为 ,新加入一位的时候,可以进一步划分原有的相等连续段,即枚举 的超集 ,预处理系数 表示给一层的 填入 的数,将大小关系 进一步划分为 ,且一层总和为 ,即 进制在这一位的值。这里复杂度

那系数 ,显然 的每个相等连续段相互独立。设 表示将一个长 的相等连续段在新的一位变为长 的大小关系 ,总和 的方案数。 就是每一段的 背包起来。但是 抗不住,可以把连续段组成相同的等价的 缩起来,这样大概只有不到 对。

然后是 ,就枚举 ,然后 dp 前 个数,最后一位选了 ,当前总和为 ,转移可能要分步。每次如果遇到 ,先强制让 ,然后 可以任意变大,对所有 一起做。复杂度

注意取模的速度。

const int p=317;
ll n;int m,q;
int a[maxm][maxm],b[maxm][maxm];
int val[10],k;
ll f[10][1<<maxm-1];
map<pii,int> mp;int idx;
int g[18000][maxn];ll g1[maxn];
int h[maxm][1<<maxm-1][maxn],h1[maxn][maxn],h2[maxn][maxn];
int coef[1<<maxm][1<<maxm-1],c1[1<<maxm];
int C[maxn][maxn];
vector<pii> to[1<<maxm-1];
inline void inc(int &u,int v){((u+=v)>=p)&&(u-=p);}
void work(){
	m=read();
	for(int i=0;i<m;i++){
		for(int j=0;j<m;j++)a[i][j]=read()%p;a[i][i]=1;
	}
	for(int i=0;i<m;i++){
		for(int j=0;j<m;j++)b[i][j]=read()%p;b[i][i]=1;
	}
	for(int i=0;i<p;i++){
		C[i][0]=1;for(int j=1;j<=i;j++)inc(C[i][j]=C[i-1][j],C[i-1][j-1]);
	}
	for(int s=1;s<(1<<m);s++){
		int val=1;
		for(int i=0;i<m;i++)if(s&(1<<i)){
			for(int j=0;j<m;j++)if(s&(1<<j))val=val*b[i][j]%p;
		}
		coef[s][0]=val;
	}
	for(int s=1;s<(1<<m);s++){
		int ss=(1<<m)-s-1;
		for(int t=ss;t;t=(t-1)&ss){
			int &val=c1[t]=1;
			for(int i=0;i<m;i++)if(t&(1<<i)){
				for(int j=0;j<m;j++)if(s&(1<<j))val=val*a[i][j]%p;
				for(int j=0;j<m;j++)if(t&(1<<j))val=val*b[i][j]%p;
			}
		}
		int sz=__builtin_popcount(s)-1;
		for(int s1=0;s1<(1<<sz);s1++)if(coef[s][s1]){
			coef[s][s1]%=p;
			for(int t=ss;t;t=(t-1)&ss){
				coef[s|t][s1|(1<<sz)]+=coef[s][s1]*c1[t];
			}
		}
	}
	for(int i=0;i<m;i++){
		for(int s=0;s<(1<<i);s++){
			for(int k=0;k<p;k++){
				for(int l=0;l<p;l++)h1[k][l]=0;
				if(k*(i+1)<p)h1[k][k]=1;
			}
			for(int j=0;j<i;j++){
				if(s&(1<<j)){
					for(int k=0;k<p-1;k++){
						for(int s=0;s+(k+1)*(i-j)<p;s++)h2[k+1][s]=h1[k][s];
					}
					for(int k=0;k<p;k++){
						for(int s=0;s+k*(i-j)<p;s++)h1[k][s]=h2[k][s],h2[k][s]=0;
					}
					for(int k=0;k<p-1;k++){
						for(int s=0;s+(k+1)*(i-j)<p;s++)h1[k+1][s]+=h1[k][s];
					}
				}
				for(int k=0;k<p;k++){
					for(int s=0;s+k*(i-j)<p;s++)if(h1[k][s])h2[k][s+k]=h1[k][s]*C[s+k][s]%p;
				}
				for(int k=0;k<p;k++){
					for(int s=0;s+k*(i-j-1)<p;s++)h1[k][s]=h2[k][s],h2[k][s]=0;
				}
			}
			for(int k=0;k<p;k++){
				for(int ss=0;ss<p;ss++)inc(h[i][s][ss],h1[k][ss]);
			}
		}
	}
	for(int s=0;s<(1<<m-1);s++){
		int ss=(1<<m-1)-1-s;
		for(int t=ss;;t=(t-1)&ss){
			vector<pii> a;
			for(int i=0,p=0;i<m;i++)if(i==m-1||(s&(1<<i))){
				int v=0;for(int j=p;j<i;j++)v|=((t>>j)&1)<<j-p;
				a.pb({i-p,v});
				p=i+1;
			}
			sort(a.begin(),a.end());
			int s0=0,s1=0,tt=0;
			for(auto[l,v]:a){
				s1+=v<<tt;
				tt+=l;
				s0|=1<<tt;
				tt++;
			}
			s0-=1<<m-1;
			if(mp.find({s0,s1})==mp.end()){
				mp[{s,t}]=++idx;
				int *gg=g[idx];
				gg[0]=1;
				for(auto[l,v]:a){
					int *hh=h[l][v];
					for(int i=0;i<p;i++){
						for(int j=0;i+j<p;j++)g1[i+j]+=gg[i]*hh[j]*C[i+j][i];
					}
					for(int i=0;i<p;i++)gg[i]=g1[i]%p,g1[i]=0;
				}
			}
			to[s].pb({t,mp[{s0,s1}]});
			if(!t)break;
		}
	}
	q=read();
	while(q--){
		n=read();
		k=0;while(n)val[++k]=n%p,n/=p;
		reverse(val+1,val+k+1);
		f[0][0]=1;
		for(int i=1;i<=k;i++){
			for(int s=0;s<(1<<m-1);s++)f[i][s]=0;
			for(int s=0;s<(1<<m-1);s++)if(f[i-1][s]){
				for(auto[t,id]:to[s])f[i][s|t]+=f[i-1][s]*g[id][val[i]];
			}
			for(int s=0;s<(1<<m-1);s++)if(f[i][s])f[i][s]%=p;
		}
		ll ans=0;for(int s=0;s<(1<<m-1);s++)ans+=f[k][s]*coef[(1<<m)-1][s];
		printf("%lld\n",ans%p);
	}
}