CF1188E Problem from Red Panda【分析性质,计数】

给定长为 \(n\) 的自然数序列 \(a_1,\cdots,a_n\),任意次操作选择 \(i\in[1,n]\),若 \(\forall j\ne i,a_j>0\) 则令 \(\forall j\ne i,a_j:=a_j-1\)\(a_i:=a_i+n-1\)

求能得到的序列 \(a\) 数量\(\bmod 998244353\)

\(n\le 10^5\)\(a_i\le 10^6\)


\(x_i\) 表示对 \(i\) 的操作次数,\(s=\sum x_i\),则一个必要条件是 \(x_i\ge\lceil\frac{s-a_i}n\rceil\)

它充分么?其实不是,比如 \(0,\cdots,0,n\) 显然一次都操作不了。

于是还有条件:\(\forall t\in[0,s)\) 满足 \(t\) 次操作之后 \(a\) 非负,则有 \(\sum_{i=1}^n\lceil\frac{\max(t-a_i,0)}n\rceil\le t\)

它充分么?感性理解一下是的

\(x\) 就可以了么?最后的 \(a_i‘=a_i+nx_i-s\),则 \(x_i\) 都不为 \(0\) 时,令所有 \(x_i:=x_i-1\) 时得到的方案等价。

\(\min x=0\)\(x\) 就可以了么?理性理解一下是的

此时 \(s\le\max a_i\),所以直接从小到大枚举 \(s\),开桶维护 \(a_i\bmod n\) 来计算 \(\sum\lceil\frac{\max(s-a_i,0)}n\rceil\),然后就是插板法。

时间复杂度 \(O(\text{Sorting}(n)+\max a_i)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5+3, M = 1100003, mod = 998244353;
template<typename T>
void rd(T &x){
	int ch = getchar(); x = 0;
	for(;ch < ‘0‘ || ch > ‘9‘;ch = getchar());
	for(;ch >= ‘0‘ && ch <= ‘9‘;ch = getchar()) x = x * 10 + ch - ‘0‘;
} 
int n, ans, a[N], cnt[N], fac[M], inv[M];
int ksm(int a, int b){
	int r = 1;
	for(;b;b >>= 1, a = (LL)a * a % mod)
		if(b & 1) r = (LL)r * a % mod;
	return r;
}
void qmo(int &x){x += x >> 31 & mod;}
int main(){
	rd(n); fac[0] = 1;
	for(int i = 0;i < n;++ i) rd(a[i]);
	sort(a, a+n);
	for(int i = 1;i < M;++ i) fac[i] = (LL)fac[i-1] * i % mod;
	inv[M-1] = ksm(fac[M-1], mod-2);
	for(int i = M-1;i;-- i) inv[i-1] = (LL)inv[i] * i % mod;
	for(int i = 0, j = 0, now = 0;i <= a[n-1];++ i){
		while(j < n && a[j] < i) ++cnt[a[j++]%n];
		if((now += cnt[(i+n-1)%n]) > i) break;
		ans = (ans + (LL)fac[i-now+n-1]*inv[i-now]) % mod;
		if(i+j>=now+n) qmo(ans -= (LL)fac[i-now+j-1]*inv[i-now+j-n]%mod); 
	} printf("%lld\n", (LL)ans*inv[n-1]%mod);
}

CF1188E Problem from Red Panda【分析性质,计数】

上一篇:给已安装的nginx添加新模块


下一篇:Django(68)drf分页器的使用