[Codeforces] combinatorics (R1600) Part.6

[Codeforces] combinatorics (R1600) Part.6

题单:https://codeforces.com/problemset?tags=combinatorics,1201-1600

1326C. Permutation Partitions

原题指路:https://codeforces.com/problemset/problem/1326/C

题意

给定一个 1 ∼ n 1\sim n 1n的排列 p 1 , ⋯   , p n p_1,\cdots,p_n p1,,pn,将其划分为不相交的 k k k段区间,使得每一段的最大值之和最大,并求取得最大值的划分方案数,后者答案对 998244353 998244353 998244353取模.设第 i    ( 1 ≤ i ≤ k ) i\ \ (1\leq i\leq k) i  (1ik)段区间为 [ l i , r i ] [l_i,r_i] [li,ri],则最大化 ∑ i = 1 k max ⁡ l i ≤ j ≤ r i p j \displaystyle \sum_{i=1}^k \max_{l_i\leq j\leq r_i} p_j i=1klijrimaxpj.

第一行输入两个整数 n , k    ( 1 ≤ k ≤ n ≤ 2 e 5 ) n,k\ \ (1\leq k\leq n\leq 2\mathrm{e}5) n,k  (1kn2e5).第二行输入一个 1 ∼ n 1\sim n 1n的排列 p 1 , ⋯   , p n p_1,\cdots,p_n p1,,pn.

思路

为使得 ∑ i = 1 k max ⁡ l i ≤ j ≤ r i p j \displaystyle \sum_{i=1}^k \max_{l_i\leq j\leq r_i} p_j i=1klijrimaxpj最大,显然应取 1 ∼ n 1\sim n 1n中的前 k k k大的数,即将它们分在不同的 k k k个区间.记录前 k k k大的数的下标 p o s [ ] pos[] pos[],则相邻两个前 k k k大的数所在的区间的分割线可取中间任一位置,将 p o s [ ] pos[] pos[]升序排列后相邻两位置的下标差之积即为方案数.

代码

const int MOD = 998244353;

void solve() {
  int n, k; cin >> n >> k;
  vii a(n);
  for (int i = 0; i < n; i++) {
    int x; cin >> x;
    a[i] = { x,i };
  }

  sort(rall(a));

  vi pos(k);  // 前k大的数的下标
  ll ans1 = 0;
  for (int i = 0; i < k; i++) {
    ans1 = ans1 + a[i].first;
    pos[i] = a[i].second;
  }

  sort(all(pos));

  int ans2 = 1;
  for (int i = 1; i < k; i++) ans2 = (ll)ans2 * (pos[i] - pos[i - 1]) % MOD;
  cout << ans1 << ' ' << ans2;
}

int main() {
  solve();
}


1328B. K-th Beautiful String

原题指路:https://codeforces.com/problemset/problem/1328/B

题意

将所有包含 ( n − 2 ) (n-2) (n2)个’a’和 2 2 2个’b’的字符串按字典序升序排列,求排名第 k k k的字符串.

t    ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t  (1t1e4)组测试数据.每组测试数据输入两个整数 n , k    ( 3 ≤ n ≤ 1 e 5 , 1 ≤ k ≤ min ⁡ { 2 e 9 , n ( n − 1 ) 2 } ) n,k\ \ \left(3\leq n\leq 1\mathrm{e}5,1\leq k\leq \min\left\{2\mathrm{e}9,\dfrac{n(n-1)}{2}\right\}\right) n,k  (3n1e5,1kmin{2e9,2n(n1)}).数据保证所有测试数据的 n n n之和不超过 1 e 5 1\mathrm{e}5 1e5.

思路

显然只需确定两个’b’所在的位置.先确定第一个’b’的位置,枚举下标 i ∈ [ n − 2 , 0 ] i\in[n-2,0] i[n2,0],若 k ≤ n − i − 1 k\leq n-i-1 kni1,则当前位置是第一个’b’的位置,进而第二个’b’的下标为 ( n − k ) (n-k) (nk);否则令 k − = n − i − 1 k-=n-i-1 k=ni1,即跳过所有当前位置为’b’的字符串.

代码

void solve() {
  int n, k; cin >> n >> k;

  string ans(n, 'a');
  for (int i = n - 2; i >= 0; k -= (n - i - 1), i--) {  // 枚举第一个'b'的位置
    if (k <= (n - i - 1)) {
      ans[i] = ans[n - k] = 'b';
      cout << ans << endl;
      return;
    }
  }
}

int main() {
  CaseT  // 单测时注释掉该行
    solve();
}


1391C. Cyclic Permutations

原题指路:https://codeforces.com/problemset/problem/1391/C

题意

给定一个 1 ∼ n 1\sim n 1n的排列 p p p,现按如下方式建立一张包含 n n n个节点的无向图:①对 ∀ i ∈ [ 1 , n ] \forall i\in[1,n] i[1,n],找到最大的 j   s . t .   1 ≤ j < i j\ s.t.\ 1\leq j<i j s.t. 1j<i p j > p i p_j>p_i pj>pi,添加一条从节点 i i i到节点 j j j的无向边;②对 ∀ i ∈ [ 1 , n ] \forall i\in[1,n] i[1,n],找到最小的 j   s . t .   i < j ≤ n j\ s.t.\ i<j\leq n j s.t. i<jn p j > p i p_j>p_i pj>pi,添加一条从节点 i i i到节点 j j j的无向边.称一个排列 p p p是循环排列,如果它对应的图中至少存在一个简单环.给定整数 n    ( 3 ≤ n ≤ 1 e 6 ) n\ \ (3\leq n\leq 1\mathrm{e}6) n  (3n1e6),求 1 ∼ n 1\sim n 1n的排列中循环排列的个数,答案对 1 e 9 + 7 1\mathrm{e}9+7 1e9+7取模.

思路

排列 p p p对应的图至少存在一个简单环当且仅当 ∃ i < j < k   s . t .   a i > a j , a k > a j \exists i<j<k\ s.t.\ a_i>a_j,a_k>a_j i<j<k s.t. ai>aj,ak>aj.显然若 p p p对应的图不存在环,则 p p p是一个单峰排列,则 a n s = n ! − c n t ans=n!-cnt ans=n!cnt,其中 c n t cnt cnt为单峰排列的个数.

设元素 n n n在下标 i i i的位置,将剩下的 ( n − 1 ) (n-1) (n1)个元素分为两组,第一组有 ( i − 1 ) (i-1) (i1)个元素,第二组有 ( n − i ) (n-i) (ni)个元素,将第一组升序排列后放在下标 i i i的左边,将第二组降序排列后放在下标 i i i的右边,有 C n − 1 i − 1 C_{n-1}^{i-1} Cn1i1种方案.故 c n t = ∑ i = 1 n C n − 1 i − 1 = ∑ i = 0 n − 1 C n − 1 i = 2 n − 1 , a n s = n ! − 2 n − 1 \displaystyle cnt=\sum_{i=1}^n C_{n-1}^{i-1}=\sum_{i=0}^{n-1}C_{n-1}^i=2^{n-1},ans=n!-2^{n-1} cnt=i=1nCn1i1=i=0n1Cn1i=2n1,ans=n!2n1.

c n t cnt cnt的另一求法:考虑构造一个单峰排列.将 n , ( n − 1 ) , ⋯   , 1 n,(n-1),\cdots,1 n,(n1),,1依次插入双端队列的队首或队尾,除元素 n n n外,其余的 ( n − 1 ) (n-1) (n1)个元素可任意选择插入队首或队尾,有 c n t = 2 n − 1 cnt=2^{n-1} cnt=2n1种方案.

代码

const int MOD = 1e9 + 7;

void solve() {
  int n; cin >> n;

  int ans = 1;
  for (int i = 2; i <= n; i++) ans = (ll)ans * i % MOD;
  cout << ((ans - qpow(2, n - 1, MOD)) % MOD + MOD) % MOD;
}

int main() {
  solve();
}


1433E. Two Round Dances

原题指路:https://codeforces.com/problemset/problem/1433/E

题意

n    ( 2 ≤ n ≤ 20 ) n\ \ (2\leq n\leq 20) n  (2n20)( n n n为偶数)个人进行两轮跳舞,每轮跳舞共 n 2 \dfrac{n}{2} 2n人,每个人只能参加其中一轮,每轮跳舞的人有序.求方案数.

思路

先从 n n n个人中选出 n 2 \dfrac{n}{2} 2n个人在第一轮跳舞,共 C n n 2 C_n^\frac{n}{2} Cn2n种方案.在选出的第一组中固定第一个跳舞的人,剩下的 ( n 2 − 1 ) \left(\dfrac{n}{2}-1\right) (2n1)个人任意排列,有 ( n 2 − 1 ) ! \left(\dfrac{n}{2}-1\right)! (2n1)!种方案,同理第二组的方案也为该数.两组人数相等,故结果要除以 2 2 2,即 a n s = C n n 2 ⋅ ( n 2 − 1 ) ! ⋅ ( n 2 − 1 ) ! 2 = n ! n 2 2 ans=\dfrac{C_n^\frac{n}{2}\cdot \left(\dfrac{n}{2}-1\right)!\cdot \left(\dfrac{n}{2}-1\right)!}{2}=\dfrac{n!}{\dfrac{n^2}{2}} ans=2Cn2n(2n1)!(2n1)!=2n2n!.

20 ! = 2432902008176640000 20!=2432902008176640000 20!=2432902008176640000,故最终结果不会爆ll.

代码

void solve() {
  int n; cin >> n;

  ll ans = 1;
  for (int i = 2; i <= n; i++) ans *= i;
  cout << ans / (n * n / 2);
}

int main() {
  solve();
}


1436C. Binary Search

原题指路:https://codeforces.com/problemset/problem/1436/C

题意

在这里插入图片描述

上述代码实现了在下标从 0 0 0开始的有序序列 a [ ] a[] a[]中查找 x x x.问 1 ∼ n 1\sim n 1n的所有排列中有多少个排列使得 x x x出现在下标 p o s pos pos(下标从 0 0 0开始)的位置,且上述代码能成功找到 x x x,答案对 1 e 9 + 7 1\mathrm{e}9+7 1e9+7取模.

第一行输入三个整数 n , x , p o s    ( 1 ≤ x ≤ n ≤ 1000 , 0 ≤ p o s ≤ n − 1 ) n,x,pos\ \ (1\leq x\leq n\leq 1000,0\leq pos\leq n-1) n,x,pos  (1xn1000,0posn1).

思路

在二分过程中,若 m i d < p o s mid<pos mid<pos,则 a m i d ≤ x a_{mid}\leq x amidx;若 m i d > p o s mid>pos mid>pos,则 a m i d > x a_{mid}>x amid>x.模拟二分过程,统计需要 < x <x <x的数的个数 c n t 1 cnt_1 cnt1和需要 > x >x >x的数的个数 c n t 2 cnt_2 cnt2,从 1 ∼ n 1\sim n 1n中的 s u m 1 sum_1 sum1 < x <x <x的数中选 c n t 1 cnt_1 cnt1个任意排列, s u m 2 sum_2 sum2 > x >x >x的数中选 c n t 2 cnt_2 cnt2个任意排列,其余 ( n − c n t 1 − c n t 2 − 1 ) (n-cnt_1-cnt_2-1) (ncnt1cnt21)个元素任意排列,其中 − 1 -1 1是去掉了 x x x,故 a n s = A s u m 1 c n t 1 ⋅ A s u m 2 c n t 2 ⋅ ( n − c n t 1 − c n t 2 − 1 ) ! ans=A_{sum_1}^{cnt_1}\cdot A_{sum_2}^{cnt_2}\cdot (n-cnt_1-cnt_2-1)! ans=Asum1cnt1Asum2cnt2(ncnt1cnt21)!.

代码

const int MAXN = 1005;
const int MOD = 1e9 + 7;
int n, x, pos;
int fac[MAXN], ifac[MAXN];

void init() {  // 预处理阶乘及其逆元
  fac[0] = 1;
  for (int i = 1; i < MAXN; i++) fac[i] = (ll)fac[i - 1] * i % MOD;

  ifac[MAXN - 1] = qpow(fac[MAXN - 1], MOD - 2, MOD);
  for (int i = MAXN - 1; i; i--) ifac[i - 1] = (ll)ifac[i] * i % MOD;
}

int A(int n, int m) {  // 排列数A(n,m)
  return (ll)fac[n] * ifac[n - m] % MOD;
}

void solve() {
  init();

  cin >> n >> x >> pos;

  int cnt1 = 0, cnt2 = 0;  // 需要<x、>x的数个数
  int l = 0, r = n;
  while (l < r) {  // 模拟二分过程
    int mid = l + r >> 1;
    if (mid <= pos) l = mid + 1, cnt1 += (mid < pos);
    else r = mid, cnt2++;
  }

  cout << (ll)A(x - 1, cnt1) * A(n - x, cnt2) % MOD * fac[n - cnt1 - cnt2 - 1] % MOD;
}

int main() {
  solve();
}


1452D. Radio Towers

原题指路:https://codeforces.com/problemset/problem/1452/D

题意 ( 2   s 2\ \mathrm{s} 2 s)

x x x轴上有编号 0 ∼ ( n + 1 ) 0\sim (n+1) 0(n+1) ( n + 2 )    ( 1 ≤ n ≤ 2 e 5 ) (n+2)\ \ (1\leq n\leq 2\mathrm{e}5) (n+2)  (1n2e5)个城市,依次在坐标 0 , ⋯   , ( n + 1 ) 0,\cdots,(n+1) 0,,(n+1)的位置.坐标 1 , ⋯   , n 1,\cdots,n 1,,n的位置上各自独立地有 1 2 \dfrac{1}{2} 21的概率造一个信号塔,每个信号塔有一个能量 p ∈ [ 1 , n ] p\in [1,n] p[1,n].若在坐标 i i i处有信号塔,则所有满足 ∣ c − i ∣ < p |c-i|<p ci<p的城市 c c c都会收到信号.现要造信号塔,使得 0 0 0号、 ( n + 1 ) (n+1) (n+1)号城市不能收到信号,且 1 , ⋯   , n 1,\cdots,n 1,,n号城市都受到且只收到一个信号塔的信号,求满足要求的概率.可以证明答案可以写成分数的形式,输出该分数模 998244353 998244353 998244353的结果.

思路

每个信号塔可视为以其为中心的一个长度为奇数的区间,问题转化为用若干个长度为奇数的区间覆盖 [ 1 , n ] [1,n] [1,n]的概率.

d p [ i ] dp[i] dp[i]表示用若干个长度为奇数的区间覆盖区间 [ 1 , i ] [1,i] [1,i]的方案数.按坐标 i i i处是否造信号塔分类:①若造,则该塔只能取 p = 1 p=1 p=1,方案数即覆盖区间 [ 1 , i − 1 ] [1,i-1] [1,i1]的方案数,即 d p [ i − 1 ] dp[i-1] dp[i1];②若不造,为使得坐标 i i i的位置被覆盖,需将当前方案的最后一个区间的长度 + = 2 +=2 +=2,即 d p [ i − 2 ] dp[i-2] dp[i2].状态转移方程: d p [ n ] = d p [ n − 1 ] + d p [ n − 2 ] dp[n]=dp[n-1]+dp[n-2] dp[n]=dp[n1]+dp[n2],即Fibonacci数列.

显然总情况数为 2 n 2^n 2n,故 a n s = f i b n 2 n ans=\dfrac{fib_n}{2^n} ans=2nfibn,其中 f i b n fib_n fibn表示Fibonacci数列的第 n n n项.

代码

const int MOD = 998244353;

void solve() {
  int n; cin >> n;

  vi fib(n + 1);
  fib[1] = 1;
  for (int i = 2; i <= n; i++) fib[i] = ((ll)fib[i - 1] + fib[i - 2]) % MOD;
  cout << qpow(qpow(2, n, MOD), MOD - 2, MOD) * fib[n] % MOD;
}

int main() {
  solve();
}


1462E1. Close Tuples (easy version)

原题指路:https://codeforces.com/problemset/problem/1462/E1

题意 ( 2   s 2\ \mathrm{s} 2 s)

给定一个长度为 n n n的序列 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an,求其中使得 i < j < z i<j<z i<j<z max ⁡ { a i , a j , a z } − min ⁡ { a i , a j , a z } ≤ 2 \max\{a_i,a_j,a_z\}-\min\{a_i,a_j,a_z\}\leq 2 max{ai,aj,az}min{ai,aj,az}2 ( i , j , z ) (i,j,z) (i,j,z)三元组的个数.

t    ( 1 ≤ t ≤ 2 e 5 ) t\ \ (1\leq t\leq 2\mathrm{e}5) t  (1t2e5)组测试数据.每组测试数据第一行输入一个整数 n    ( 1 ≤ n ≤ 2 e 5 ) n\ \ (1\leq n\leq 2\mathrm{e}5) n  (1n2e5).第二行输入 n n n个整数 a 1 , ⋯   , a n    ( 1 ≤ a i ≤ n ) a_1,\cdots,a_n\ \ (1\leq a_i\leq n) a1,,an  (1ain).数据保证所有测试数据的 n n n之和不超过 2 e 5 2\mathrm{e}5 2e5.

思路

满足条件的有序三元组 ( a i , a j , a z ) (a_i,a_j,a_z) (ai,aj,az)有如下几类:① ( x , x + 2 , x + 2 ) (x,x+2,x+2) (x,x+2,x+2);② ( x , x + 1 , x + 2 ) (x,x+1,x+2) (x,x+1,x+2);③ ( x , x + 1 , x + 1 ) (x,x+1,x+1) (x,x+1,x+1);④ ( x , x , x + 2 ) (x,x,x+2) (x,x,x+2);⑤ ( x , x , x + 1 ) (x,x,x+1) (x,x,x+1);⑥ ( x , x , x ) (x,x,x) (x,x,x).统计每个数出现的次数,枚举三元组的最小元素 x x x,组合数即可.

代码

ll C(int n, int m) {  // 组合数C(n,m)
  if (n <= m) return n == m;
  else {
    ll res = 1;
    for (int i = n - m + 1; i <= n; i++) res = res * i / (i - n + m);
    return res;
  }
}

void solve() {
  int n; cin >> n;
  vi cnt(n + 5);  // 防止越界
  for (int i = 0; i < n; i++) {
    int a; cin >> a;
    cnt[a]++;
  }

  ll ans = 0;
  for (int i = 1; i <= n; i++) {
    ans += (ll)cnt[i] * C(cnt[i + 2], 2);
    ans += (ll)cnt[i] * cnt[i + 1] * cnt[i + 2];
    ans += (ll)cnt[i] * C(cnt[i + 1], 2);
    ans += C(cnt[i], 2) * cnt[i + 2];
    ans += C(cnt[i], 2) * cnt[i + 1];
    ans += C(cnt[i], 3);
  }
  cout << ans << endl;
}

int main() {
  CaseT  // 单测时注释掉该行
    solve();
}


1475C. Ball in Berland

原题指路:https://codeforces.com/problemset/problem/1475/C

题意 ( 2   s 2\ \mathrm{s} 2 s)

有编号 1 ∼ a 1\sim a 1a a a a个男生和编号 1 ∼ b 1\sim b 1b b b b个女生,他们组成了 k k k对舞伴 ( x , y )    ( 1 ≤ x ≤ a , 1 ≤ y ≤ b ) (x,y)\ \ (1\leq x\leq a,1\leq y\leq b) (x,y)  (1xa,1yb).从中选出两对舞伴,使得选中的 4 4 4个人不同,求方案数.

t    ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t  (1t1e4)组测试数据.每组测试数据第一行输入三个整数 a , b , k    ( 1 ≤ a , b , k ≤ 2 e 5 ) a,b,k\ \ (1\leq a,b,k\leq 2\mathrm{e}5) a,b,k  (1a,b,k2e5).第二行输入 k k k个整数 a 1 , ⋯   , a k a_1,\cdots,a_k a1,,ak,分别表示每对舞伴中男生的编号.第三行输入 k k k个整数 b 1 , ⋯   , b k b_1,\cdots,b_k b1,,bk,分别表示每对舞伴中女生的编号.数据保证每组测试数据给定的 k k k对舞伴相异,且所有测试数据的 a , b , k a,b,k a,b,k之和不超过 2 e 5 2\mathrm{e}5 2e5.

思路

c n t a [ a i ] cnta[a_i] cnta[ai]表示 a i a_i ai号男生在舞伴中出现的次数, c n t b [ b i ] cntb[b_i] cntb[bi]表示 b i b_i bi号女生在舞伴中出现的次数.对第 i i i对舞伴,其对答案的贡献为总舞伴数 − a [ i ] -a[i] a[i]的重复次数 − b [ i ] -b[i] b[i]的重复次数 + 1 +1 +1,其中 + 1 +1 +1是因为 ( a [ i ] , b [ i ] ) (a[i],b[i]) (a[i],b[i])多减了一次.因每队舞伴都被多算了一次,故最后答案需除以 2 2 2.

代码

void solve() {
  int n, m, k; cin >> n >> m >> k;
  vi a(k), b(k);
  vi cnta(n + 1);  // cnta[a[i]]表示a[i]号男生在舞伴中出现的次数
  vi cntb(m + 1);  // cntb[b[i]]表示b[i]号男生在舞伴中出现的次数
  for (int i = 0; i < k; i++) {
    cin >> a[i];
    cnta[a[i]]++;
  }
  for (int i = 0; i < k; i++) {
    cin >> b[i];
    cntb[b[i]]++;
  }

  ll ans = 0;
  for (int i = 0; i < k; i++) ans += k - cnta[a[i]] - cntb[b[i]] + 1;
  cout << ans / 2 << endl;
}

int main() {
  CaseT  // 单测时注释掉该行
    solve();
}


1475E. Advertising Agency

原题指路:https://codeforces.com/problemset/problem/1475/E

题意 ( 2   s 2\ \mathrm{s} 2 s)

编号 1 ∼ n 1\sim n 1n n n n个博主分别有 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an个粉丝,假定任一粉丝只关注一个博主.现要请 k k k个博主,使得所有粉丝数之和最大,求方案数,答案对 1 e 9 + 7 1\mathrm{e}9+7 1e9+7取模.

t    ( 1 ≤ t ≤ 1000 ) t\ \ (1\leq t\leq 1000) t  (1t1000)组测试数据.每组测试数据第一行输入两个整数 n , k    ( 1 ≤ k ≤ n ≤ 1000 ) n,k\ \ (1\leq k\leq n\leq 1000) n,k  (1kn1000).第二行输入 n n n个整数 a 1 , ⋯   , a n    ( 1 ≤ a i ≤ n ) a_1,\cdots,a_n\ \ (1\leq a_i\leq n) a1,,an  (1ain).数据保证所有测试数据的 n n n之和不超过 1000 1000 1000.

思路

将博主按粉丝数降序排列,贪心地选前 k k k个博主.若遇到粉丝数相同的博主,组合数即可.

代码

const int MAXN = 1005;
const int MOD = 1e9 + 7;
int fac[MAXN], ifac[MAXN];

void init() {  // 预处理阶乘及其逆元
  fac[0] = 1;
  for (int i = 1; i < MAXN; i++) fac[i] = (ll)fac[i - 1] * i % MOD;

  ifac[MAXN - 1] = qpow(fac[MAXN - 1], MOD - 2, MOD);
  for (int i = MAXN - 1; i; i--) ifac[i - 1] = (ll)ifac[i] * i % MOD;
}

int C(int n, int m) {  // 组合数C(n,m)
  return (ll)fac[n] * ifac[m] % MOD * ifac[n - m] % MOD;
}

void solve() {
  int n, k; cin >> n >> k;
  vi cnt(n + 1);
  for (int i = 0; i < n; i++) {
    int a; cin >> a;
    cnt[a]++;
  }

  for (int i = n; i >= 0; i--) {
    if (cnt[i] >= k) {
      cout << C(cnt[i], k) << endl;
      return;
    }
    else k -= cnt[i];
  }
}

int main() {
  init();
  CaseT  // 单测时注释掉该行
    solve();
}


1513B. AND Sequences

原题指路:https://codeforces.com/problemset/problem/1513/B

题意 ( 2   s 2\ \mathrm{s} 2 s)

称一个长度为 n    ( n ≥ 2 ) n\ \ (n\geq 2) n  (n2)的序列 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an是好的,如果对 ∀ i ∈ [ 1 , n − 1 ] \forall i\in [1,n-1] i[1,n1],都有 a 1 & ⋯ & a i = a i + 1 & ⋯ & a n a_1\& \cdots\& a_i=a_{i+1}\& \cdots \& a_n a1&&ai=ai+1&&an.给定一个序列 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an,求有多少个 1 ∼ n 1\sim n 1n的排列 p 1 , ⋯   , p n   s . t .   a p 1 , ⋯   , a p n p_1,\cdots,p_n\ s.t.\ a_{p_1},\cdots,a_{p_n} p1,,pn s.t. ap1,,apn是好的,答案对 1 e 9 + 7 1\mathrm{e}9+7 1e9+7取模.

t    ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t  (1t1e4)组测试数据.每组测试数据第一行输入一个整数 n    ( 2 ≤ n ≤ 2 e 5 ) n\ \ (2\leq n\leq 2\mathrm{e}5) n  (2n2e5).第二行输入 n n n个整数 a 1 , ⋯   , a n    ( 0 ≤ a i ≤ 1 e 9 ) a_1,\cdots,a_n\ \ (0\leq a_i\leq 1\mathrm{e}9) a1,,an  (0ai1e9).数据保证所有测试数据的 n n n之和不超过 2 e 5 2\mathrm{e}5 2e5.

思路

若序列 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an是好的,则 a 1 = a 2 & ⋯ & a n a_1=a_2\& \cdots\& a_n a1=a2&&an,两边与 a 1 a_1 a1 a 1 = a 1 & ⋯ & a n a_1=a_1\& \cdots\& a_n a1=a1&&an,同理 a n = a 1 & ⋯ & a n a_n=a_1\& \cdots\& a_n an=a1&&an,即序列首尾的数只能是序列所有元素的与.

a 1 = a n = a 1 & ⋯ & a n = x a_1=a_n=a_1\& \cdots\& a_n=x a1=an=a1&&an=x,则 x ≤ min ⁡ { a 1 , ⋯   , a n } x\leq \min\{a_1,\cdots,a_n\} xmin{a1,,an}.显然确定 a 1 a_1 a1 a n a_n an后,任一前缀与、后缀与都分别由 a 1 a_1 a1 a n a_n an决定,故中间的 ( n − 2 ) (n-2) (n2)个元素可任意排列.设序列中值为 x x x的元素的个数为 c n t cnt cnt,则 a n s = A x 2 ⋅ ( n − 2 ) ! ans=A_x^2\cdot (n-2)! ans=Ax2(n2)!.

代码

const int MAXN = 2e5 + 5;
const int MOD = 1e9 + 7;
int fac[MAXN], ifac[MAXN];

void init() {  // 预处理阶乘及其逆元
  fac[0] = 1;
  for (int i = 1; i < MAXN; i++) fac[i] = (ll)fac[i - 1] * i % MOD;

  ifac[MAXN - 1] = qpow(fac[MAXN - 1], MOD - 2, MOD);
  for (int i = MAXN - 1; i; i--) ifac[i - 1] = (ll)ifac[i] * i % MOD;
}

int A(int n, int m) {  // 排列数A(n,m)
  if (n < m) return 0;
  else return (ll)fac[n] * ifac[n - m] % MOD;
}

void solve() {
  int n; cin >> n;
  vi a(n);
  int tmp = INT_MAX;
  for (auto& ai : a) {
    cin >> ai;
    tmp &= ai;
  }

  int cnt = count(all(a), tmp);
  cout << (ll)A(cnt, 2) * fac[n - 2] % MOD << endl;
}

int main() {
  init();
  CaseT  // 单测时注释掉该行
    solve();
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,Codeforces Round 511 (Div. 1)是一个比赛的名称。然而,引用内容中没有提供与这个比赛相关的具体信息或问题。因此,我无法回答关于Codeforces Round 511 (Div. 1)的问题。如果您有关于这个比赛的具体问题,请提供更多的信息,我将尽力回答。 #### 引用[.reference_title] - *1* [Codeforces Round 860 (Div. 2)题解](https://blog.csdn.net/qq_60653991/article/details/129802687)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces Round 867 (Div. 3)(A题到E题)](https://blog.csdn.net/wdgkd/article/details/130370975)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Codeforces Round 872 (Div. 2)(前三道](https://blog.csdn.net/qq_68286180/article/details/130570952)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值