zoukankan      html  css  js  c++  java
  • [CF1188E] Problem from Red Panda

    [题目链接]

    https://codeforces.com/contest/1188/problem/E

    [题解]

    (x_{i}) 表示 (i) 被选中的次数 , 考虑 ({x_i}) 合法的条件 , 令 (s = sum{x_{i}})

    首先需要保证最终数组中的每个元素非负 , 故 (a_{i} - s + k cdot x_{i} geq 0) , 也就是 (x_igelceilfrac{max(s-a_i,0)}k ceil)

    此外 , 还需判断每轮后是否能使得每个元素都非负 , 假设当前是第 (t) 轮 , 不妨将每个 (a_{i}) 都减去 (t) , 再用 (t)(k) 填补空缺 , 需要满足 (sum_{i=1}^klceilfrac{max(t-a_i,0)}k ceille t) , 在第一个条件的限制下 , 每个元素不会被加超过 (x_{i}) 次。

    故一个 ({x_i}) 满足条件当且仅当 :

    (1). (x_igelceilfrac{max(s-a_i,0)}k ceil)

    (2). 对于 (0le tle s) , 都有 (sum_{i=1}^klceilfrac{max(t-a_i,0)}k ceille t)

    计算 (sum_{i=1}^klceilfrac{max(t-a_i,0)}k ceille t) 是容易的 , 只需对于 (a_{i} < s) 的部分开一个桶维护 (a_{i} mod k) 即可。

    考虑当所有 (x_{i}) 非负时 , 将其全部减一本质上是同一种情况。

    结论 :所有至少有一个数未操作的不同的 ({x_i}) , 两两本质不同

    证明 :

    ((1).) 若操作集合相同 , 若操作次数不同 , 因为有数没被操作 , 故最终得到的序列必然本质不同; 若操作次数相同 , 则必能找到两个数使其得到的结果不同。

    ((2).) 若操作集合不同 , 设 (i) 在第一个序列未被操作但在第二个序列中被操作 , (j) 在第一个序列被操作但在第二个序列中未被操作。 若操作次数相同 , 那么有 (delta a_{i , 1} = -cnt , delta a_{i , 2} = C cdot k - cnt eq delta a_{i , 1})。若操作次数不同 , (delta a_{i , 1} = -cnt_{1} , delta a_{j , 2} = -cnt_{2})。 因为 (a_{j , 1} = C dot k - cnt_{1} = -cnt_{2}) , 所以 (cnt_{1} >cnt_{2}) , 同理又有 (cnt_{2} > cnt_{1}) , 矛盾。

    故我们成功地将问题转化为对 ({x_i}) 计数。不难发现新问题中 (s) 的规模被缩小至 (max{a_{i}})

    也就是说 , 问题变为了 :

    (k) 个变量 , 其中有 (r) 个 ((a_{i} < s) 的个数) 有一个取值下界 (lim_{i})(lim_{i} geq 1) , 求这 (k) 个变量中至少有一个为 (0) 且总和为 (s) 的方案数。

    不妨令 (w = sum{lim_{i}})

    考虑容斥原理 , 用总方案数减去至少有一个 (0) 的方案数 , 这两者都可以用组合数学中经典的 "插板法" 求解。

    答案为 (inom{s-w+k-1}{k-1}-inom{s-w+r-1}{k-1})

    故时间复杂度 (O(max{a_{i}} + KlogK))

    [代码]

    #include<bits/stdc++.h>
    
    using namespace std;
    
    typedef long long LL;
    
    #define rep(i , l , r) for (int i = (l); i < (r); ++i)
    
    const int MN = 2e6 + 5 , mod = 998244353;
    
    int K , N , A[MN] , fac[MN] , ifac[MN] , cnt[MN];
    
    inline void inc(int &x , int y) {
    	x = x + y < mod ? x + y : x + y - mod;
    }
    inline void dec(int &x , int y) {
    	x = x - y >= 0 ? x - y : x - y + mod;
    }
    inline int qPow(int a , int b) {
    	int c = 1;
    	for (; b; b >>= 1 , a = 1ll * a * a % mod) if (b & 1) c = 1ll * c * a % mod;
    	return c;
    }
    inline void init(int n) {
    	fac[0] = 1;
    	for (int i = 1; i <= n; ++i) fac[i] = 1ll * fac[i - 1] * i % mod;
    	ifac[n] = qPow(fac[n] , mod - 2);
    	for (int i = n - 1; i >= 0; --i) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
    }
    inline int binom(int n , int m) {
    	if (n < m) return 0;
    	else return 1ll * fac[n] * ifac[m] % mod * ifac[n - m] % mod;
    }
    
    int main() {
    	
    	 init(2e6);
    	 scanf("%d" , &K); int cur = 0;
    	 for (int i = 1; i <= K; ++i) scanf("%d" , &A[i]) , N += A[i];
    	 sort(A + 1 , A + 1 + K); int ans = 0;
    	 for (int i = 0 , j = 1;  i <= A[K]; ++i) {
    	 	  while (A[j] < i) ++cnt[A[j++] % K];
    	 	  cur += cnt[(i - 1 + K) % K];
    	 	  if (cur > i) {
    	 	  	  printf("%d
    " , ans);
    			  return 0;	
    		  }
    		  inc(ans , binom(i - cur + K - 1 , K - 1));
    		  if (i - cur + j - 2 >= K - 1)
    		  	  dec(ans , binom(i - cur + j - 2 , K - 1));
    	 }
    	 printf("%d
    " , ans);
         return 0;
    }
  • 相关阅读:
    推箱子(简易版)
    [LeetCode] Word Ladder II
    [LeetCode] Path Sum
    [LeetCode] Word Ladder
    DFS & BFS
    [LeetCode] Surrounded Regions
    [LeetCode] Add Binary
    [LeetCode] Plus One
    [LeetCode] Single Number II
    [LeetCode] Single Number
  • 原文地址:https://www.cnblogs.com/evenbao/p/14354437.html
Copyright © 2011-2022 走看看