1. 程式人生 > 其它 >11.17 模擬賽

11.17 模擬賽

禁止以一切形式傳播或轉載

T1:

給出 \(n,a,c\),求 \(\sum_{i=0}^n\left\lfloor\frac{a\times i}{c}\right\rfloor\),保證 \(c\mid n\)。結果對 \(998244353\) 取模。

\(n,a,c\le10^9\).

解:

\[\begin{aligned} \sum_{i=0}^n\left\lfloor\frac{a\times i}{c}\right\rfloor&=\sum_{i=0}^n \left(\frac{a\times n}{c}-\left\lceil\frac{a\times(n-i)}{c}\right\rceil\right)\\ &=\sum_{i=0}^n \left(\frac{a\times n}{c}-\left\lceil\frac{a\times i}{c}\right\rceil\right)\\ &=\sum_{i=0}^n\left(\frac{a\times n}{c}-\left(\left\lfloor\frac{a\times i}{c}\right\rfloor+1-\left[c\mid(a\times i)\right]\right)\right)\\ &=\left(n+1\right)\left(\frac{a\times n}{c}-1\right)+\sum_{i=0}^n\left[c\mid(a\times i)\right]-\sum_{i=0}^n\left\lfloor\frac{a\times i}{c}\right\rfloor\\ &=\left(n+1\right)\left(\frac{a\times n}{c}-1\right)+\frac{n\times\gcd(a,c)}{c}+1-\sum_{i=0}^n\left\lfloor\frac{a\times i}{c}\right\rfloor\\ \sum_{i=0}^n\left\lfloor\frac{a\times i}{c}\right\rfloor&=\frac{n\times\left(a\times\left(n+1\right)-c+\gcd(a,c)\right)}{2\times c} \end{aligned} \]

T2:

長度為 \(n\) 的數列,求其 \(k\) 階字首和 \(S_i^{(k)}\),答案對 \(998244353\) 取模。

\(n\le10^5,k\le2^{60}\).

解:

約定:

\[\large \begin{aligned} F_k(x)&=\sum_{i=0}^{n-1}S_{i+1}^{(k)}x^i\\ G(x)&=\sum_{i=0}^{n-1}x^i \end{aligned} \]

展開相乘,明顯可知在 \(mod\ x^n\) 意義下:

\[\large \begin{aligned} \because S_i^{(k+1)}&=\sum_{j=1}^iS_j^{(k)}\\ \therefore F_k(x)\times G(x)&=\sum_{i=0}^{n-1}S_{i+1}^{(k)}x^i\sum_{j=0}^{n-1}x^j\\ &=\sum_{j=0}^{n-1}\sum_{i=0}^{n-1}S_{i+1}^{(k)}x^{i+j}\\ &\equiv\sum_{j=0}^{n-1}\sum_{i=0}^{n-j-1}S_{i+1}^{(k)}x^{i+j}\\ &\equiv\sum_{j=0}^{n-1}S_{n-j}^{(k+1)}x^{n-j-1}\\ &\equiv\sum_{j=0}^{n-1}S_{j+1}^{(k+1)}x^j\\ &\equiv F_{k+1}(x)\ (mod\ x^n) \end{aligned} \]

故所求 \(S_i^{(k)}\)

\((F_0(x)\times(G(x))^k)[i-1]\)\(F_0(x)\)\(0\) 階字首和(原數列)的生成函式 \(\sum_{i=0}^{n-1}a_{i+1}x^i\)

考慮 \((G(x))^k[i]\) 的意義:有 \(k\) 個數,每個數在 \([0,k-1]\) 之間,每個數的和為 \(i\) 的方案數。因為 \(i\le k-1\),所以不用擔心上界問題,就相當於 \(k\) 個自然數的和為 \(i\) 的方案數。

眾所周知方案數可以用插板法求出:\(i+k-1\) 個位置選出 \(k-1\) 個作為板,每相鄰板之間的距離為一個數的大小。即:\(C_{i+k-1}^{k-1}\)

。直接遞推就行。

最後用 \(\text{NTT}\)\(F_0(x)\)\((G(x))^k\) 的卷積。

時間複雜度 \(O(n\log n)\)

#include <bits/stdc++.h>

#define N 800000
#define mod 998244353
#define int long long

using namespace std;

template <typename T>
inline void read (T &a) {
	T x = 0, f = 1;
	char ch = getchar ();
	while (! isdigit (ch)) {
		(ch == '-') and (f = 0);
		ch = getchar ();
	}
	while (isdigit (ch)) {
		x = (x << 1) + (x << 3) + (ch xor '0');
		ch = getchar ();
	}
	a = f ? x : -x;
}
template <typename T, typename ...A>
inline void read (T &t, A &...a) {
	read (t), read (a...);
}
template <typename T>
inline void print (T x) {
	if (x < 0) putchar ('-'), x = -x;
	if (x > 9) print (x / 10);
	putchar (x % 10 + '0');
}

inline int qpow (int a, int b) {
	int res = 1;
	while (b) {
		(b bitand 1) and (res = res * a % mod);
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}

int a[N], b[N], n, k, len;

inline void NTT (int *a, int n, int f) {
	for (int i = k = 0; i < n; i++) {
		if (i > k) swap (a[i], a[k]);
		for (int j = n >> 1; (k xor_eq j) < j; j >>= 1);
	}
	for (int k = 2; k <= n; k <<= 1) {
		int tmp = qpow (3, (mod - 1) / k * f);
		for (int i = 0; i < n; i += k) {
			int w = 1, t;
			for (int j = i; j < i + (k >> 1); j++, w = w * tmp % mod) {
				t = w * a[j + (k >> 1)] % mod;
				a[j + (k >> 1)] = (a[j] - t + mod) % mod;
				a[j] = (a[j] + t) % mod;
			}
		}
	}
}

signed main () {
	freopen ("b.in", "r", stdin);
	freopen ("b.out", "w", stdout);
	read (n, k), b[0] = len = 1, k %= mod;
	for (int i = 0; i < n; i++) read (a[i]);
	for (int i = 1; i < n; i++) {
		b[i] = b[i - 1] * (k + i - 1) % mod * qpow (i, mod - 2) % mod;
	}
	while (len < (n << 1)) len <<= 1;
	NTT (a, len, 1);
	NTT (b, len, 1);
	for (int i = 0; i < len; i++) a[i] = a[i] * b[i] % mod;
	NTT (a, len, mod - 2);
	for (int i = 0; i < n; i++) {
		print (a[i] * qpow (len, mod - 2) % mod);
		puts ("");
	}
}

T3:

給出 \(n\) 個數 \(a_1,a_2,\cdots,a_n\),求出一個排列, 滿足前 \(i\in[1,n]\) 個數的中位數單調不下降,輸出字典序最大的排列。

解:

\(a\) 從小到大排序:

\(a_{\left\lceil\frac{n}{2}\right\rceil}=a_{\left\lceil\frac{n}{2}\right\rceil+1}\),則在構造過程中,可以讓任意時刻的中位數等於 \(a_{\left\lceil\frac{n}{2}\right\rceil}\),維護兩個堆 \(a\)\(b\),分別存大於和小於 \(a_{\left\lceil\frac{n}{2}\right\rceil}\) 的數,構造時,先彈出 \(a_{\left\lceil\frac{n}{2}\right\rceil}\)\(a_{\left\lceil\frac{n}{2}\right\rceil+1}\),之後再從 \(a\) 中彈出最大的,再從 \(b\) 中彈出最大的,以此類推。

如果存在 \(k<\left\lceil\frac{n}{2}\right\rceil\)\(a_k=a_{k+1}\),與上類似。

否則選第一個數。

中位數顯然要用對頂堆啊

#include <bits/stdc++.h>

#define N 100010

using namespace std;

template <typename T>
inline void read (T &a) {
	T x = 0, f = 1;
	char ch = getchar ();
	while (! isdigit (ch)) {
		(ch == '-') and (f = 0);
		ch = getchar ();
	}
	while (isdigit (ch)) {
		x = (x << 1) + (x << 3) + (ch xor '0');
		ch = getchar ();
	}
	a = f ? x : -x;
}
template <typename T, typename ...A>
inline void read (T &t, A &...a) {
	read (t), read (a...);
}
template <typename T>
inline void print (T x) {
	if (x < 0) putchar ('-'), x = -x;
	if (x > 9) print (x / 10);
	putchar (x % 10 + '0');
}

multiset <int> s;
priority_queue <int> A, B;
int a[N], v[N], n, p, q, mid;

inline void push (int x) {
	if (A.empty () or x <= A.top ()) A.push (x);
	else B.push (-x);
	if (A.size () < B.size ()) A.push (-B.top ()), B.pop ();
	if (A.size () > B.size () + 1) B.push (-A.top ()), A.pop ();
}

signed main () {
	freopen ("c.in", "r", stdin);
	freopen ("c.out", "w", stdout);
	read (n);
	for (int i = 1; i <= n; i++) read (a[i]);
	sort (a + 1, a + n + 1);
	mid = n + 1 >> 1;
	if (a[mid] == a[mid + 1]) {
		while (mid < n and a[mid] == a[mid + 1]) mid++;
		print (a[mid]);
		p = mid - 1, q = n;
		while (p or q > mid) {
			if (p) printf (" "), print (a[p--]);
			if (q > mid) printf (" "), print (a[q--]);
		}
		return 0;
	}
	while (mid > 1 and a[mid] != a[mid - 1]) mid--;
	print (a[mid]);
	v[mid] = 1;
	p = mid - 1, q = n;
	while (p and q > mid) {
		printf (" "), print (a[p]);
		v[p--] = 1;
		printf (" "), print (a[q]);
		v[q--] = 1;
	}
	for (int i = 1; i <= n; i++) {
		if (v[i]) push (a[i]);
		else s.insert (a[i]);
	}
	while (s.size ()) {
		p = *s.begin ();
		if (A.size () == B.size ()) {
			if (p >= -B.top ()) q = *--s.end ();
			else q = *s.begin ();
		} else {
			if(B.size () and p * 2 >= A.top () - B.top ()) q = *--s.end ();
            else q = *--s.upper_bound (p * 2 - A.top ());
		}
		printf (" "), print (q);
		s.erase (s.find (q)), push (q);
	}
}