CF1603E A Perfect Problem gxy001

注:完美为 perfect,好的为 good。好的序列为 min×max\min\times\max\ge\sum 的序列,完美的序列为每个子序列都好的序列。

首先,我们考虑排好序的完美序列,任意完美的序列的任意排列都是完美的。

然后我们发现:

定理 1 一个排好序的序列是完美的当且仅当其每个子区间都是好的。

证明:枚举每个 iijj,我们发现 min×max=ai×aj\min\times\max=a_i\times a_j 固定 \sum 最大时即为选择整个子区间 [i,j][i,j] 时。

定理 2 一个排好序的序列是完美的当且仅当其每个前缀都是好的。

证明:此时,aiaja1ajk=1jajk=ijaja_ia_j\ge a_1a_j\ge \sum\limits_{k=1}^j a_j\ge \sum\limits_{k=i}^j a_j,则有每个前缀是好的可以推出每个子区间是好的。

定理 3 k,akk\forall k,a_k\ge k

证明:若 ak<ka_k<ki=1kaika1>a1ak\sum\limits_{i=1}^ka_i\ge ka_1>a_1a_k,违反定理 2。

定理 4ak=ka_k=k,则 ik,ai=k\forall i\le k,a_i=k

证明:由定理 2 a1ak=ka1i=1kaia_1a_k=ka_1\ge \sum\limits_{i=1}^ka_i,又因为 mini=1kai=a1\min\limits_{i=1}^ka_i=a_1,所以 ka1i=1kaika_1\le \sum\limits_{i=1}^ka_i,所以 ka1=i=1kaika_1=\sum\limits_{i=1}^ka_i ,所以 ik,ai=k\forall i\le k,a_i=k

定理 5an=n+1,i<n,aii+1a_n=n+1,\exist i<n,a_i\ge i+1,且 a1na_{1\sim n} 为好序列,则前缀 a1ia_{1\sim i} 为好序列。

证明:(n+1)a1k=1nak(n+1)a_1\ge \sum\limits_{k=1}^n a_k,则 a1k=1n(aka1)k=1i(aka1)a_1\ge \sum\limits_{k=1}^n (a_k-a_1)\ge\sum\limits_{k=1}^i (a_k-a_1),则 aia1(i+1)a1k=1iaka_ia_1\ge (i+1)a_1\ge \sum\limits_{k=1}^i a_k

分两个情况讨论 an=na_n=nan=n+1a_n=n+1,前一种情况是平凡的(因为定理 4),我们只考虑 an=n+1a_n=n+1,则此时 aa 为完美的充要条件为:

  • ia1,a1ain+1\forall i\le a_1,a_1\le a_i\le n+1
  • i>a1,i+1ain+1\forall i>a_1,i+1\le a_i\le n+1
  • i=1n(aia1)a1\sum\limits_{i=1}^n(a_i-a_1)\le a_1

但是,我们要求的序列是没有排序的,让我们把每个数都减去 a1a_1,然后称之为 bb

枚举 a1a_1,则我们要计数这样的数列 bb

  • 0bin+1a10\le b_i\le n+1-a_1
  • ba1\sum b\le a_1
  • 至少存在 i(1ina1)i(1\le i\le n-a_1) 个数 n+2ia1\ge n+2-i-a_1

我们设 fi,s,kf_{i,s,k} 为已经确定 ii 个元素,当前和为 ss,要放置值等于 kk 的数的方案数,枚举放了几个 kkfi,s,k=jfi+j,s+jk,k1j!f_{i,s,k}=\sum\limits_{j}\frac{f_{i+j,s+jk,k-1}}{j!},边界为 i=ni=n 时,值为 n!n!

DP 应该是 O(n3logn)O(n^3\log n)log\log 是枚举 jj 的调和级数),加上枚举 aia_i 的复杂度,复杂度为 O(n4logn)O(n^4\log n)

定理 6 a1<n2na_1<n-2\sqrt n 时,答案为 00

证明:因为条件至少存在 i(1ina1)i(1\le i\le n-a_1) 个数 n+2ia1\ge n+2-i-a_1,若 a1<n2na_1<n-2\sqrt nbi>n+1>a1\sum b_i>n+1>a_1,所以无解。

复杂度 O(n3nlogn)O(n^3\sqrt n\log n),可以通过本题。

#include<cstdio>
#include<cmath>
#include<algorithm>
typedef unsigned long long ull;
typedef __uint128_t L;
struct FastMod {
    ull b, m;
    FastMod(ull b) : b(b), m(ull((L(1) << 64) / b)) {}
    ull operator ()(ull a) {
        ull q = (ull)((L(m) * a) >> 64);
        ull r = a - q * b; // can be proven that 0 <= r < 2*b
        return r >= b ? r - b : r;
    }
}mod(2);
int p,n,fac[210],ifac[210];
int pow(int x,int y){
	int res=1;
	while(y){
		if(y&1) res=mod(1ll*res*x);
		x=mod(1ll*x*x),y>>=1; 
	}
	return res;
}
int main(){
	scanf("%d%d",&n,&p);
	mod=FastMod(p);
	fac[0]=1;
	for(int i=1;i<=n;i++) fac[i]=mod(1ll*fac[i-1]*i);
	ifac[n]=pow(fac[n],p-2);
	for(int i=n;i;i--) ifac[i-1]=mod(1ll*ifac[i]*i);
	int ans=0;
	int lim=2*sqrt(n)+1;
	for(int a1=std::max(1,n-lim);a1<=n;a1++){
		static int f[210][210][210];
		for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) for(int k=0;k<=n;k++) f[i][j][k]=0;
		for(int i=0;i<=n;i++)
			for(int sum=0;sum<=a1;sum++)
				f[i][sum][0]=mod(1ll*fac[n]*ifac[n-i]);
		for(int k=1;k<=n+1-a1;k++){
			for(int i=0;i<n;i++)
				for(int sum=0;sum<=a1;sum++){
					int &ans=f[i][sum][k];
					int r=(a1-sum)/k;
					for(int cnt=std::min(r,n-i);~cnt;--cnt)if(k<=1||i+cnt>=n-a1+2-k){
						ans=mod(ans+1ll*f[i+cnt][sum+cnt*k][k-1]*ifac[cnt]);
					}
				}
			for(int sum=0;sum<=a1;sum++) f[n][sum][k]=fac[n];
		}
		ans=mod(ans+f[0][0][n+1-a1]);
	}
	printf("%d\n",ans);
	return 0;
}
Powered By Valine
v1.4.14
欢迎来到本站!