AT5695「AGC041D」Problem Scores

Address

Solution

  • 嘗試簡化第三個限制,設 k=n12k = \lfloor \dfrac{n - 1}{2}\rfloor,我們取前 k+1k + 1 個數作爲第一個集合,取後 kk 個數作爲第二個集合,因爲這兩個集合的差是所有選集合的方案中最小的,所以只要這兩個集合滿足條件,所有的集合都能滿足條件。

Algorithm 1

  • 因爲 nn 的奇偶性會影響中間是否會多出一個數,我們分情況討論:

    1. nn 是偶數,枚舉第 k+2k + 2 個數爲 xx,那麼對剩下的數有如下要求:

      1. xx 與前 k+1k + 1 個數的差 [0,x)\in [0,x) 且差遞減;
      2. kk 個數與 xx 的差 [0,nx]\in [0,n-x] 且差遞增;
      3. xx 與前 k+1k + 1 個數的差的和加上後 kk 個數與 xx 的差的和小於 xx

      fi,jf_{i,j} 表示已經確定了前 ii 個數、xx 與這些數的差的和爲 jj 的方案數。

      轉移即從大到小枚舉差 l(l[0,n))l(l \in [0,n)),令 fi+1,j+l=fi+1,j+l+fi,jf_{i + 1,j + l} = f_{i + 1,j + l} + f_{i,j}

      由於第二維 jnj \le n,存在合法方案時一定有 ilnil \le n,時間複雜度 O(n2lnn)\mathcal O(n^2 \ln n)

      kk 個數的方案可以看做是選取若干個後綴區間 +1,設 gi,jg_{i,j} 表示已經選了 ii 個後綴、這些後綴的長度之和爲 jj 的方案數。

      轉移即從大到小枚舉後綴長度 l(l[0,k])l(l \in [0,k]),令 gi+1,j+l=gi+1,j+l+gi,jg_{i + 1,j + l} = g_{i + 1,j + l} + g_{i,j},時間複雜度同樣是 O(n2lnn)\mathcal O(n^2 \ln n)

      最後的答案即爲:
      x=1ni=0x1fk+1,ij=0xi1gnx,j \begin{aligned}\sum \limits_{x = 1}^{n} \sum \limits_{i = 0}^{x - 1} f_{k + 1,i} \sum \limits_{j = 0}^{x - i - 1}g_{n-x,j}\end{aligned}
      預處理 gg 第二維的前綴和即可 O(n2)\mathcal O(n^2) 計算。

    2. nn 是奇數,枚舉第 k+1k + 1 個數爲 xx,只要最後算答案時把 fk+1,if_{k+1,i} 改爲 fk,if_{k,i},其它部分與偶數的情況完全相同。

  • 總的時間複雜度 O(n2lnn)\mathcal O(n^2 \ln n)

Code 1

#include <bits/stdc++.h>

const int N = 5005;
int f[N][N], g[N][N];
int n, ans, mod;

inline void add(int &x, int y)
{
	x += y;
	x >= mod ? x -= mod : 0;
}

int main()
{
	scanf("%d%d", &n, &mod);	
	int k = n - 1 >> 1;
	f[0][0] = g[0][0] = 1;
	for (int c = n - 1; c >= 0; --c)
		for (int i = 0, im = !c ? n : n / c; i <= im; ++i)
			for (int j = 0; j <= n - c; ++j)
				add(f[i + 1][j + c], f[i][j]);
	for (int c = k; c >= 0; --c)
		for (int i = 0, im = !c ? n : n / c; i <= im; ++i)
			for (int j = 0; j <= n - c; ++j)
				add(g[i + 1][j + c], g[i][j]);
	for (int i = 0; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			add(g[i][j], g[i][j - 1]);
	if (!(n & 1))
	{
		for (int x = 1; x <= n; ++x)
			for (int j = 0; j < x; ++j)
				ans = (1ll * f[k + 1][j] * g[n - x][x - j - 1] + ans) % mod;
	}
	else
	{
		for (int x = 1; x <= n; ++x)
			for (int j = 0; j < x; ++j)
				ans = (1ll * f[k][j] * g[n - x][x - j - 1] + ans) % mod;
	} 
	printf("%d\n", ans);
	return 0;
}

Algorithm 2

  • 考慮將 AA 數組差分,去掉單調性的限制,令差分數組爲 BB

  • B0=1B_0 = 1,則 Ai=1+j=1iBjA_i = 1 + \sum \limits_{j = 1}^{i}B_j,因此其中一個限制條件就是 i=1nBi<n\sum \limits_{i = 1}^{n} B_i < n

  • 同樣對 nn 的奇偶性進行討論:

    1. nn 爲奇數,n12+1=n+12\lfloor \dfrac{n - 1}{2} \rfloor + 1 = \dfrac{n + 1}{2},列出限制條件:
      i=1n+12Ai>i=n+12+1nAii=1n+12(1+j=1iBj)>i=n+12+1n(1+j=1iBj)2i=1n+12j=1iBji=1nj=1iBj2i=1n+12(n+12i+1)Bii=1n(ni+1)Bi \begin{aligned}\sum \limits_{i = 1}^{\frac{n + 1}{2}}A_i &> \sum \limits_{i = \frac{n + 1}{2} + 1}^{n} A_i \\\sum \limits_{i = 1}^{\frac{n + 1}{2}}(1 + \sum \limits_{j = 1}^{i}B_j) &> \sum \limits_{i = \frac{n + 1}{2} + 1}^{n}(1 + \sum \limits_{j = 1}^{i}B_j) \\2\sum \limits_{i = 1}^{\frac{n + 1}{2}}\sum \limits_{j = 1}^{i}B_j &\ge \sum \limits_{i = 1}^{n}\sum \limits_{j = 1}^{i}B_j \\2\sum \limits_{i = 1}^{\frac{n + 1}{2}}(\dfrac{n + 1}{2} - i + 1)B_i &\ge \sum \limits_{i = 1}^{n}(n - i + 1)B_i\\\end{aligned}
      簡單移項後,我們可以得到:
      i=1nCiBi0 \begin{aligned} \sum \limits_{i = 1}^{n}C_iB_i \le 0 \end{aligned}
      其中:
      Ci={i21in+12ni+1n+12<in C_i = \begin{cases}i - 2 &1 \le i \le \dfrac{n + 1}{2} \\n - i + 1 &\dfrac{n + 1}{2} < i \le n\\\end{cases}

    2. nn 爲偶數,同樣可以推出 CiC_i 的表達式:
      Ci={i21in2+1ni+1n2+1<in C_i = \begin{cases}i - 2 &1\le i \le \dfrac{n}{2} + 1\\n - i + 1 &\dfrac{n}{2} + 1 < i \le n\\\end{cases}
      整理一下,我們有:
      Ci={i21in2+1ni+1n2+1in C_i = \begin{cases}i - 2 &1\le i \le \lfloor \dfrac{n}{2} \rfloor + 1\\n - i + 1 &\lfloor \dfrac{n}{2} \rfloor + 1 \le i \le n\\\end{cases}
      注意到只有 C1C_1 是負數,考慮列出所有和 B1B_1 有關的限制條件:
      {B1n1i=2nBiB1i=2nCiBi \begin{cases}B_1 \le n - 1 - \sum \limits_{i = 2}^{n}B_i \\B_1 \ge \sum \limits_{i = 2}^{n}C_i B_i \\ \end{cases}
      在已知 Bi(2in)B_i(2 \le i \le n) 的情況下,合法的 B1B_1 的個數爲:
      max{0,ni=2n(Ci+1)Bi} \begin{aligned}\max\{0, n - \sum \limits_{i = 2}^{n}(C_i + 1)B_i\}\end{aligned}

  • fjf_j 表示 i=2n(Ci+1)Bi=j\sum \limits_{i = 2}^{n}(C_i + 1)B_i = j 的方案數,最後的答案就爲 i=0n1(nj)fj\sum \limits_{i = 0}^{n - 1}(n - j)f_j

  • 顯然 fjf_j 的轉移是一個完全揹包,時間複雜度 O(n2)\mathcal O(n^2)

Code 2

#include <bits/stdc++.h>

const int N = 1e4 + 5;
int n, mod, ans, c[N], f[N];

inline void add(int &x, int y)
{
	x += y;
	x >= mod ? x -= mod : 0;
}

int main()
{
	scanf("%d%d", &n, &mod);
	int half = n >> 1;
	for (int i = 2; i <= half + 1; ++i)
		c[i] = i - 1;
	for (int i = half + 2; i <= n; ++i)
		c[i] = n - i + 2;

	f[0] = 1;
	for (int i = 2; i <= n; ++i)
		for (int j = c[i]; j < n; ++j)
			add(f[j], f[j - c[i]]);
	for (int j = 0; j < n; ++j)
		ans = (1ll * (n - j) * f[j] + ans) % mod;
	printf("%d\n", ans);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章