当前位置: 首页 > news >正文

[Codeforces] combinatorics (R1600) Part.2

[Codeforces] combinatorics (R1600) Part.2

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

288B. Polo the Penguin and Houses

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

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

有编号 1 ∼ n 1\sim n 1n n n n个房间,其中 i i i号房间上有一个数字 p i ∈ [ 1 , n ] p_i\in [1,n] pi[1,n].玩家在 i i i号房间时,下一个房间要前往的房间是 p i p_i pi.已知玩家从编号 1 ∼ k 1\sim k 1k的房间出发时,他能走到 1 1 1号房间;从编号 ( k + 1 ) ∼ n (k+1)\sim n (k+1)n的房间出发时,他不能走到 1 1 1号房间;从 1 1 1号房间出发时,他能经若干步返回 1 1 1号房间.求有多少组 p 1 , ⋯   , p n p_1,\cdots,p_n p1,,pn满足上述条件,答案对 1 e 9 + 7 1\mathrm{e}9+7 1e9+7取模.

第一行输入两个整数 n , k    ( 1 ≤ n ≤ 1000 , 1 ≤ k ≤ min ⁡ { 8 , n } ) n,k\ \ (1\leq n\leq 1000,1\leq k\leq \min\{8,n\}) n,k  (1n1000,1kmin{8,n}).

[简单题意] 构造一个包含编号 1 ∼ n 1\sim n 1n个节点的有向图,其中 1 ∼ k 1\sim k 1k号节点都存在到达 1 1 1号节点的路径, ( k + 1 ) ∼ n (k+1)\sim n (k+1)n号节点都不存在到达 1 1 1号节点的路径,求方案数.

思路

①对 1 ∼ k 1\sim k 1k号节点,先构造一个包含 k k k个节点的Cayley树,有 k k − 2 k^{k-2} kk2种方案.任选一个节点为根节点,有 k k k种方案.

​ 取 p i = f a i , p r o o t = 1 p_i=fa_i,p_{root}=1 pi=fai,proot=1,在树上加一条边使得出现一个包含节点 1 1 1的有向环,显然这是满足条件的.

②对 ( k + 1 ) ∼ n (k+1)\sim n (k+1)n号节点,每个节点都能与 ( k + 1 ) ∼ n (k+1)\sim n (k+1)n号节点中的任一节点相连,有 ( n − k ) n − k (n-k)^{n-k} (nk)nk种方案.

综上, a n s = k k − 1 ( n − k ) n − k ans=k^{k-1}(n-k)^{n-k} ans=kk1(nk)nk.

代码

const int MOD = 1e9 + 7;

void solve() {
  int n, k; cin >> n >> k;
  cout << qpow(k, k - 1, MOD) * qpow(n - k, n - k, MOD) % MOD;
}

int main() {
  solve();
}


319A. Malek Dance Club

原题指路:https://codeforces.com/problemset/problem/319/A

题意

2 n 2^n 2n个男生和 2 n 2^n 2n个女生,分别编号 1 ∼ ( 2 n − 1 ) 1\sim (2^n-1) 1(2n1).给定一个 n n n位二进制数 x x x,要求 i i i号男生与 ( i   x o r   x ) (i\ \mathrm{xor}\ x) (i xor x)号女生组队,记作 ( i , i   x o r   x ) (i,i\ \mathrm{xor}\ x) (i,i xor x).定义一个组队方案的复杂程度为满足 a < c a<c a<c b > d b>d b>d的数对 ( a , b ) (a,b) (a,b) ( c , d ) (c,d) (c,d)的个数,求该方案的复杂程度,答案对 1 e 9 + 7 1\mathrm{e}9+7 1e9+7取模.

第一行输入一个长度为 n    ( 1 ≤ n ≤ 100 ) n\ \ (1\leq n\leq 100) n  (1n100)的二进制数 x x x.

思路I

考察一个两边各包含编号 0 ∼ ( 2 n − 1 ) 0\sim (2^n-1) 0(2n1) 2 n 2^n 2n个节点的二分图,将组队的节点间连线,显然任意两线段的交点会使得复杂程度 + 1 +1 +1.

如下图,考察在 0 − 1 0-1 01 x x x前补 0 0 0和补 1 1 1产生的影响:

=在这里插入图片描述

①在 x x x前补 0 0 0时,相同的结构复制了一遍.

②在 x x x前补 1 1 1时,相同的结构复制了一遍后,右边节点的上半部分与下半部分交换.

设长度为 n n n 0 − 1 0-1 01 x x x的复杂程度为 f ( x ‾ ) f(\overline{x}) f(x),则 f ( 0 x ‾ ) = 2 f ( x ) , f ( 1 x ‾ ) = 2 f ( x ) + 2 2 n f(\overline{0x})=2f(x),f(\overline{1x})=2f(x)+2^{2n} f(0x)=2f(x),f(1x)=2f(x)+22n.

由数学归纳法: a n s = x ⋅ 2 n − 1 ans=x\cdot 2^{n-1} ans=x2n1.注意要对二进制数 x x x做大数取模.

代码I

const int MOD = 1e9 + 7;

void solve() {
  string s; cin >> s;
  reverse(all(s));

  int n = s.length();
  int x = 0;
  for (int i = 0; i <= n; i++) 
    if (s[i] == '1') x = ((ll)x + qpow(2, i, MOD)) % MOD;
  cout << qpow(2, n - 1, MOD) * x % MOD;
}

int main() {
    solve();
}

思路II

注意到 0 ∼ ( 2 n − 1 ) 0\sim (2^n-1) 0(2n1)的二进制表示中,前 2 n − 1 2^{n-1} 2n1个数的首位为 0 0 0,后 2 n − 1 2^{n-1} 2n1个数的首位为 1 1 1.

x x x首位为 0 0 0时,原数异或后首位不变,则 0 ∼ ( 2 n − 1 ) 0\sim (2^n-1) 0(2n1)中的逆序对数即 0 ∼ ( 2 n − 1 − 1 ) 0\sim (2^{n-1}-1) 0(2n11)中的逆序对数 + 2 n − 1 ∼ ( 2 n − 1 ) +2^{n-1}\sim (2^n-1) +2n1(2n1)中的逆序对数.注意到这两部分数除首位外相同,而首位不共线复杂程度,故答案即第一部分的复杂程度 × 2 \times 2 ×2.

x x x首位为 1 1 1时,原数异或后首位取反,则异或后的数中前 2 n − 1 2^{n-1} 2n1个数 > > > 2 n − 1 2^{n-1} 2n1个数,这导致在情况①的基础上增加了 2 n − 1 ⋅ 2 n − 1 = 2 2 ( n − 1 ) 2^{n-1}\cdot 2^{n-1}=2^{2(n-1)} 2n12n1=22(n1)个逆序对.

0 ∼ ( 2 n − 1 ) 0\sim (2^n-1) 0(2n1)异或上 x x x得到的逆序对数为 f ( n , x ) f(n,x) f(n,x), x x x去掉首位后的数为 g ( x ) g(x) g(x), x x x的首位为 h ( x ) h(x) h(x),

f ( n , x ) = { 0 , n = 1 且 x = 0 1 , n = 1 且 x = 1 2 ⋅ f ( n − 1 , g ( x ) ) , h ( x ) = 0 2 ⋅ f ( n − 1 , g ( x ) ) + 2 2 ( n − 1 ) , h ( x ) = 1 f(n,x)=\begin{cases}0,n=1\text{且}x=0 \\ 1,n=1\text{且}x=1 \\ 2\cdot f(n-1,g(x)),h(x)=0 \\ 2\cdot f(n-1,g(x))+2^{2(n-1)},h(x)=1 \end{cases} f(n,x)= 0,n=1x=01,n=1x=12f(n1,g(x)),h(x)=02f(n1,g(x))+22(n1),h(x)=1,递归求即可.

代码II

const int MAXN = 205;  // 两倍空间
const int MOD = 1e9 + 7;
char x[MAXN];
int len;
int pow2[MAXN];

void init() {
  pow2[0] = 1;
  for (int i = 1; i < MAXN; i++) pow2[i] = (ll)pow2[i - 1] * 2 % MOD;
}

int f(int pos) {
  if (pos == len - 1) return x[pos] == '1';
  else if (x[pos] == '0') return (ll)f(pos + 1) * 2 % MOD;
  else return ((ll)f(pos + 1) * 2 % MOD + pow2[2 * (len - pos - 1)]) % MOD;
}

void solve() {
  init();

  cin >> x;
  len = strlen(x);

  cout << f(0);  // 从最高位开始计算
}

int main() {
  solve();
}


322B. Ciel and Flowers

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

题意

有红、绿、蓝三种花各 r r r g g g b    ( 0 ≤ r , g , b ≤ 1 e 9 ) b\ \ (0\leq r,g,b\leq 1\mathrm{e}9) b  (0r,g,b1e9)种,用于制作如下四种花束:①红花束,需 3 3 3朵红花;②绿花束,需 3 3 3朵绿花;③蓝花束,需 3 3 3朵蓝花;④混合花束,需红、绿、蓝三种花各 1 1 1朵.问最多能制作多少花束.

思路I

常见错误 a n s = ⌊ r 3 ⌋ + ⌊ g 3 ⌋ + ⌊ b 3 ⌋ + min ⁡ { r   m o d   3 , g   m o d   3 , b   m o d   3 } ans=\left\lfloor\dfrac{r}{3}\right\rfloor+\left\lfloor\dfrac{g}{3}\right\rfloor+\left\lfloor\dfrac{b}{3}\right\rfloor+\min\{r\ \mathrm{mod}\ 3,g\ \mathrm{mod}\ 3,b\ \mathrm{mod}\ 3\} ans=3r+3g+3b+min{r mod 3,g mod 3,b mod 3},hack数据 r = 2 , g = 2 , b = 3 r=2,g=2,b=3 r=2,g=2,b=3.

分析知只有 r , g , b r,g,b r,g,b(无序)模 3 3 3的余数分别为 0 , 2 , 2 0,2,2 0,2,2且余数为 0 0 0的花不少于 3 3 3朵时答案会 + 1 +1 +1,特判即可.

代码I

void solve() {
  vi a(3);
  for (auto& ai : a) cin >> ai;

  sort(all(a), [&](const int& A, const int& B) {
    return A % 3 < B % 3;
  });

  int ans = a[0] / 3 + a[1] / 3 + a[2] / 3 + min({ a[0] % 3, a[1] % 3, a[2] % 3 });
  if (a[0] >= 3 && a[0] % 3 == 0 && a[1] % 3 == 2 && a[2] % 3 == 2) ans++;
  cout << ans;
}

int main() {
  solve();
}

思路II

存在最优策略,其中包含的混合花束 < 3 <3 <3.

[] 若有 3 3 3个混合花束,则将其拆解为红花束、绿花束、蓝花束各 1 1 1个,答案不会变差.

枚举制作 0 , 1 , 2 0,1,2 0,1,2个混合花束,求答案的最大值.

代码II

void solve() {
  int r, g, b; cin >> r >> g >> b;

  int ans = r / 3 + g / 3 + b / 3 + min({ r % 3,g % 3,b % 3 });  // 0个混合花束
  if (r >= 1 && g >= 1 && b >= 1)  // 1个混合花束
    ans = max(ans, (r - 1) / 3 + (g - 1) / 3 + (b - 1) / 3 + min({ (r + 2) % 3, (g + 2) % 3, (b + 2) % 3 }) + 1);
  if (r >= 2 && g >= 2 && b >= 2)  // 2个混合花束
    ans = max(ans, (r - 2) / 3 + (g - 2) / 3 + (b - 2) / 3 + min({ (r + 1) % 3, (g + 1) % 3, (b + 1) % 3 }) + 2);
  cout << ans;
}

int main() {
  solve();
}


323A. Black-and-White Cube

原题指路:https://codeforces.com/problemset/problem/323/A

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

给定一个由 k × k × k    ( 1 ≤ k ≤ 100 ) k\times k\times k\ \ (1\leq k\leq 100) k×k×k  (1k100)个小正方体组成的大正方体.两小正方体视为相邻,如果它们有公共面.现要给每个小正方体的每个面染黑色或白色,使得每个白色的正方体恰有 2 2 2个相邻的白色正方体,每个黑色的正方体恰有 2 2 2个相邻的黑色正方体.若有解,输出任一种方案;否则输出 − 1 -1 1.

若有解,前 k k k行输出一个 k × k k\times k k×k的由字符’b’和’w’组成的字符矩阵,表示大正方体第一层的染色情况.接下来 k k k行同理,表示大则会那个方体第二层的染色情况,以此类推.

思路

k k k为奇数时,手模样例知无解.

k k k为偶数时,每层的构造如下图所示,同时保证上层与下层异色即可.

在这里插入图片描述

代码

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

  if (n & 1) {
    cout << -1;
    return;
  }

  vector<vi> a(n + 1, vi(n + 1));
  for (int c = 1; c <= n; c++) {  // c的奇偶性代表颜色
    for (int i = c; i <= n - c + 1; i++) {
      for (int j = c; j <= n - c + 1; j++) {
        if (i == c || i == n - c + 1) a[i][j] = c & 1;
        else if (j == c || j == n - c + 1) a[i][j] = c & 1;
        else a[i][j] = (c & 1) ^ 1;
      }
    }
  }

  for (int k = 1; k <= n; k++) {  // 枚举大正方体的每一层
    for (int i = 1; i <= n; i++) {
      for (int j = 1; j <= n; j++) {
        cout << (a[i][j] ? 'w' : 'b');
        a[i][j] ^= 1;
      }
      cout << endl;
    }
  }
}

int main() {
  solve();
}


340C. Tourist Problem

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

题意

给定一个长度为 n    ( 2 ≤ n ≤ 1 e 5 ) n\ \ (2\leq n\leq 1\mathrm{e}5) n  (2n1e5)的序列 a 1 , ⋯   , a n    ( 1 ≤ a i ≤ 1 e 7 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}7) a1,,an  (1ai1e7).对 a [ ] a[] a[]的所有排列 a p 1 , ⋯   , a p n a_{p_1},\cdots,a_{p_n} ap1,,apn,求所有的 ∣ a p 1 − 0 ∣ + ∑ i = 2 n ∣ a p i − a p i − 1 ∣ \displaystyle |a_{p_1}-0|+\sum_{i=2}^n |a_{p_i}-a_{p_{i-1}}| ap10∣+i=2napiapi1之和的平均值,输出既约分数的分子和分母.

思路

①对 ∣ a p 1 − 0 ∣ |a_{p_1}-0| ap10∣,固定每个 a i a_i ai作为第一个数,其余 ( n − 1 ) (n-1) (n1)个数任排,它对答案的贡献为 ∑ i = 1 n a i ( n − 1 ) ! \displaystyle\sum_{i=1}^n a_i(n-1)! i=1nai(n1)!.

②对 ∑ i = 2 n ∣ a p i − a p i − 1 ∣ \displaystyle \sum_{i=2}^n |a_{p_i}-a_{p_{i-1}}| i=2napiapi1,枚举每个相邻的 ( i , j ) (i,j) (i,j),它可排在排列的 ( n − 1 ) (n-1) (n1)个位置上,其余 ( n − 2 ) (n-2) (n2)个数任排, 它对答案的贡献为 ∑ i = 1 n ∑ j = 1 n ∣ a i − a j ∣ ⋅ ( n − 1 ) ⋅ ( n − 2 ) ! = ∑ i = 1 n ∑ j = 1 n ∣ a i − a j ∣ ⋅ ( n − 1 ) ! \displaystyle\sum_{i=1}^n \sum_{j=1}^n |a_i-a_j|\cdot (n-1)\cdot (n-2)!=\sum_{i=1}^n \sum_{j=1}^n |a_i-a_j|\cdot (n-1)! i=1nj=1naiaj(n1)(n2)!=i=1nj=1naiaj(n1)!.

a n s = ( ∑ i = 1 n ∑ j = 1 n ∣ a i − a j ∣ + ∑ i = 1 n a i ) ⋅ ( n − 1 ) ! n ! = ∑ i = 1 n ∑ j = 1 n ∣ a i − a j ∣ + ∑ i = 1 n a i n ans=\dfrac{\left(\displaystyle \sum_{i=1}^n \sum_{j=1}^n |a_i-a_j|+\sum_{i=1}^n a_i\right)\cdot (n-1)!}{n!}=\dfrac{\displaystyle \sum_{i=1}^n \sum_{j=1}^n |a_i-a_j|+\sum_{i=1}^n a_i}{n} ans=n!(i=1nj=1naiaj+i=1nai)(n1)!=ni=1nj=1naiaj+i=1nai.

暴力求时间复杂度 O ( n 2 ) O(n^2) O(n2),会TLE.考虑优化,先将 a [ ] a[] a[]升序排列,则 ∑ i = 1 n ∑ j = 1 n ∣ a i − a j ∣ = 2 ∑ i = 1 n ∑ j = 1 i − 1 ( a i − a j ) = 2 ∑ i = 1 n ( i − 1 ) a i − ∑ j = 1 i − 1 a j \displaystyle \sum_{i=1}^n \sum_{j=1}^n |a_i-a_j|=2\sum_{i=1}^n \sum_{j=1}^{i-1}(a_i-a_j)=2\sum_{i=1}^n (i-1)a_i-\sum_{j=1}^{i-1} a_j i=1nj=1naiaj=2i=1nj=1i1(aiaj)=2i=1n(i1)aij=1i1aj,在计算的过程中维护 a [ ] a[] a[]的前缀和 p r e pre pre即可将计算答案的时间复杂度优化道 O ( n ) O(n) O(n).

代码

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

  sort(a.begin() + 1, a.end());

  ll pre = 0;  // a[]的前缀和
  for (int i = 1; i <= n; i++) {
    ans += ((ll)(i - 1) * a[i] - pre) * 2;
    pre += a[i];
  }

  ll g = gcd(ans, n);
  cout << ans / g << ' ' << n / g;
}

int main() {
  solve();
}


364A. Matrix

原题指路:https://codeforces.com/problemset/problem/364/A

题意

给定一个只包含数码的字符串 s s s,定义 b i j = s i ⋅ s j b_{ij}=s_i\cdot s_j bij=sisj,在矩阵 B = ( b i j ) B=(b_{ij}) B=(bij)中求满足矩形中的元素之和等于 a a a的矩形的个数.

第一行输入一个整数 a    ( 0 ≤ a ≤ 1 e 9 ) a\ \ (0\leq a\leq 1\mathrm{e}9) a  (0a1e9).第二行输入一个长度不超过 4000 4000 4000的只包含数码的字符串 s s s.

思路

a n s = ∑ i = 1 n ∑ j = 1 n ∑ k = i n ∑ l = j n [ ∑ p = i k ∑ q = j l s p ⋅ s q = a ] = ∑ i = 1 n ∑ j = 1 n ∑ k = i n ∑ l = j n [ ( ∑ p = i k s p ) ( ∑ q = j l s q ) = a ] \displaystyle ans=\sum_{i=1}^n \sum_{j=1}^n \sum_{k=i}^n \sum_{l=j}^n \left[\sum_{p=i}^k \sum_{q=j}^l s_p\cdot s_q=a\right]=\sum_{i=1}^n \sum_{j=1}^n \sum_{k=i}^n \sum_{l=j}^n \left[\left(\sum_{p=i}^k s_p\right)\left(\sum_{q=j}^l s_q\right)=a\right] ans=i=1nj=1nk=inl=jn[p=ikq=jlspsq=a]=i=1nj=1nk=inl=jn[(p=iksp)(q=jlsq)=a].

维护 s [ ] s[] s[]的前缀和 p r e [ ] pre[] pre[],预处理出所有 ∑ i = 1 n ∑ j = i n ( p r e [ j ] − p r e [ i − 1 ] ) \displaystyle\sum_{i=1}^n \sum_{j=i}^n (pre[j]-pre[i-1]) i=1nj=in(pre[j]pre[i1]),存在哈希表 m p [ ] mp[] mp[]中,

​ 则 a n s = ∑ i = 1 n ∑ j = i n [ p r e [ j ] − p r e [ i − 1 ] ≠ 0 ] ⋅ [ ( p r e [ j ] − p r e [ i − 1 ] ) ∣ a ] ⋅ m p [ a p r e [ j ] − p r e [ i − 1 ] ] \displaystyle ans=\sum_{i=1}^n \sum_{j=i}^n [pre[j]-pre[i-1]\neq 0]\cdot [(pre[j]-pre[i-1])\mid a]\cdot mp\left[\dfrac{a}{pre[j]-pre[i-1]}\right] ans=i=1nj=in[pre[j]pre[i1]=0][(pre[j]pre[i1])a]mp[pre[j]pre[i1]a].

注意特判 a = 0 a=0 a=0的特殊i情况.

代码

const int MAXN = 4005;
int a;
char s[MAXN];
int pre[MAXN];  // s[]的前缀和
umap<int, int> mp;

void solve() {
  cin >> a >> s + 1;

  int n = strlen(s + 1);
  for (int i = 1; i <= n; i++) pre[i] = pre[i - 1] + s[i] - '0';

  for (int i = 1; i <= n; i++)
    for (int j = i; j <= n; j++) mp[pre[j] - pre[i - 1]]++;

  if (!a) cout << (ll)mp[0] * n * (n + 1) - (ll)mp[0] * mp[0];
  else {
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
      for (int j = i; j <= n; j++) {
        int tmp = pre[j] - pre[i - 1];
        if (tmp && a % tmp == 0) ans += mp[a / tmp];
      }
    }
    cout << ans;
  }
}

int main() {
  solve();
}


374B. Inna and Nine

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

题意

给定一个长度不超过 1 e 5 1\mathrm{e}5 1e5的只包含数码的字符串 s s s.现有操作:取两相邻的数码使得它们之和为 9 9 9,将这两个数码合并为一个数码 9 9 9.问经若干次操作后包含最多个数码 9 9 9的数的个数.数据保证答案不超过ll.

思路

定义一个 b l o c k block block是一个区间,其中任意两相邻数之和都为 9 9 9.

①对长度为偶数的 b l o c k block block,如 3636 3636 3636,若合并中间两个数码,则会导致结果少一个数码 9 9 9,显然这不是最优的.

​ 故长度为偶数的 b l o c k block block只有一种情况.

②对长度为奇数的 b l o c k block block,最优策略操作后剩下一个单独的数码,则合并该 b l o c k block block的方案数为 ⌈ l e n 2 ⌉ \left\lceil\dfrac{len}{2}\right\rceil 2len,其中 l e n len len为区间长度.

代码

const int MAXN = 1e5 + 5;
char s[MAXN];
int block[MAXN], idx;  // 每个block的长度、当前block的编号

void solve() {
  cin >> s + 1;

  int n = strlen(s + 1);
  bool ok = false;  // 记录当前是否在block中
  for (int i = 2; i <= n; i++) {
    if (s[i] - '0' + s[i - 1] - '0' == 9) {
      if (!ok) {
        ok = true;
        block[++idx] = 1;
      }
      block[idx]++;
    }
    else ok = false;
  }

  ll ans = 1;
  for (int i = 1; i <= idx; i++)
    if (block[i] & 1) ans *= (block[i] + 1) / 2;
  cout << ans;
}

int main() {
  solve();
}


414B. Mashmokh and ACM

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

题意

称一个整数序列 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an是好的,如果 a i ∣ a i + 1    ( 1 ≤ i ≤ n − 1 ) a_i\mid a_{i+1}\ \ (1\leq i\leq n-1) aiai+1  (1in1).给定整数 n , k    ( 1 ≤ n , k ≤ 2000 ) n,k\ \ (1\leq n,k\leq 2000) n,k  (1n,k2000),求长度为 k k k的、元素范围为 [ 1 , n ] [1,n] [1,n]的好的整数序列的个数,答案对 1 e 9 + 7 1\mathrm{e}9+7 1e9+7取模.

思路

d p [ i ] [ j ] dp[i][j] dp[i][j]表示长度为 i i i的、以 j j j结尾的好的序列的个数.枚举 j j j的约数 d d d,状态转移方程 d p [ i ] [ j ] = ∑ d ∣ x d p [ i − 1 ] [ d ] \displaystyle dp[i][j]=\sum_{d\mid x}dp[i-1][d] dp[i][j]=dxdp[i1][d].初始条件可取 d p [ 0 ] [ 1 ] = 1 dp[0][1]=1 dp[0][1]=1.

暴力转移时间复杂度 O ( k n n ) O(kn\sqrt{n}) O(knn ),会TLE.考虑优化,先预处理出 2000 2000 2000内所有数的约数,总时间复杂度 O ( k n log ⁡ n ) O(kn\log n) O(knlogn).

代码

const int MAXN = 2005;
const int MOD = 1e9 + 7;
vi divisors[MAXN];  // 存每个数的约数
int dp[MAXN][MAXN];  // dp[i][j]表示长度为i的、以j结尾的好的序列的个数

void init() {
	for (int i = 1; i < MAXN; i++)
		for (int j = i; j < MAXN; j += i) divisors[j].push_back(i);
}

void solve() {
	init();

	int n, k; cin >> n >> k;
	
	dp[0][1] = 1;
	for (int i = 1; i <= k; i++) {
		for (int j = 1; j <= n; j++) {
			for (auto d : divisors[j])
				dp[i][j] = ((ll)dp[i][j] + dp[i - 1][d]) % MOD;
		}
	}

	int ans = 0;
	for (int i = 1; i <= n; i++) ans = ((ll)ans + dp[k][i]) % MOD;
	cout << ans;
}

int main() {
	solve();
}


459B. Pashmak and Flowers

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

题意

给定一个长度为 n    ( 2 ≤ n ≤ 2 e 5 ) n\ \ (2\leq n\leq 2\mathrm{e}5) n  (2n2e5)的序列 a 1 , ⋯   , a n    ( 1 ≤ a i ≤ 1 e 9 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}9) a1,,an  (1ai1e9).从中选出两个元素,使得最大元素与最小元素之差 d i f f diff diff最大,且选出的数中最大元素的出现次数不超过 1 1 1,输出 d i f f diff diff和方案数.若选出的两个元素相等,则视其中一个为最大元素,另一个为最小元素,进而该方案也视为合法方案.

思路

①若序列的所有元素都相等,则 a n s = C n 2 ans=C_n^2 ans=Cn2.

②若序列存在不相等的元素,设序列的最大元素、最小元素出现次数分别为 c n t 1 , c n t 2 cnt_1,cnt_2 cnt1,cnt2,则 a n s = c n t 1 ⋅ c n t 2 ans=cnt_1\cdot cnt_2 ans=cnt1cnt2.

代码

void solve() {
  int n; cin >> n;
  vi a(n);
  int maxnum = -INF, minnum = INF;
  for (auto& ai : a) {
    cin >> ai;
    maxnum = max(maxnum, ai), minnum = min(minnum, ai);
  }

  cout << maxnum - minnum << ' ';
  cout << (maxnum - minnum ? (ll)count(all(a), maxnum) * count(all(a), minnum) : (ll)n * (n - 1) / 2);
}

int main() {
  solve();
}


476B. Dreamoon and WiFi

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

题意

某人在数轴上移动,初始时在原点.给定一个只包含字符’+‘和’-‘的字符串 s 1 s_1 s1,其中’+‘表示向右移动一个单位,’-‘表示向左移动一个单位.给定一个与 s 1 s_1 s1等长的、只包含字符’+‘、’-‘和’?‘的字符串 s 2 s_2 s2,其中’?‘等概率地取’+‘或’-'.分别进行操作 s 1 s_1 s1和操作 s 2 s_2 s2,求最后停在同一位置的概率,误差不超过 1 e − 9 1\mathrm{e}-9 1e9.

第一行输入一个只包含字符’+‘和’-‘的字符串 s 1 s_1 s1.第二行输入一个与 s 1 s_1 s1等长的、只包含字符’+‘、’-‘和’?'的字符串 s 2 s_2 s2.数据保证两字符串的长度都不超过 10 10 10.

思路I

显然操作 s 1 s_1 s1后停在的位置 t a r g e t target target可求得.

显然 s 2 s_2 s2中’?‘的位置不影响概率,可先求出只操作 s 2 s_2 s2中确定的字符后停在的位置 l a s t last last,并统计 s 2 s_2 s2中’?'的个数 u n k n o w n unknown unknown.

考察两终点的距离(相差的 + 1 +1 +1数) d i s = t a r g e t − l a s t dis=target-last dis=targetlast.

d i s dis dis u n k n o w n unknown unknown奇偶性不同或 u n k n o w n < a b s ( d i s ) unknown<abs(dis) unknown<abs(dis)时无解,概率为 0 0 0.

②设从 l a s t last last走到 t a r g e t target target所需的步数为 n e e d need need,则 n e e d − ( u n k n o w n − n e e d ) = ∣ d i s ∣ need-(unknown-need)=|dis| need(unknownneed)=dis,解得 n e e d = ⌊ u n k n o w n + ∣ d i s ∣ 2 ⌋ need=\left\lfloor\dfrac{unknown+|dis|}{2}\right\rfloor need=2unknown+dis.

a n s = C u n k n o w n n e e d 2 u n k n o w n ans=\dfrac{C_{unknown}^{need}}{2^{unknown}} ans=2unknownCunknownneed.

代码I

void solve() {
	string s1, s2; cin >> s1 >> s2;

	int target = 0;  // s1序列的终点
	for (int i = 0; i < s1.length(); i++)
		target += s1[i] == '+' ? 1 : -1;

	int last = 0;  // s2已知序列的终点
	int unknown = 0;  // s2中的?数
	for (int i = 0; i < s2.length(); i++) {
		if (s2[i] == '?') unknown++;
		else last += s2[i] == '+' ? 1 : -1;
	}
	
	int dis = target - last;  // 两终点相差的+1数
	if ((dis + unknown & 1) || unknown < abs(dis)) {
		cout << 0;
		return;
	}

	int need = unknown + abs(dis) >> 1;  // 到达终点所需的步数
	int ans = 1;
	for (int i = 0; i < need; i++) ans *= unknown - i;
	for (int i = 2; i <= need; i++) ans /= i;
	cout << fixed << setprecision(18) << (double)ans / (1 << unknown);
}

int main() {
	solve();
}

思路II

因’?‘的个数至多有 10 10 10个,可枚举每个’?'取何值.


思路III

d p [ i ] [ j ] dp[i][j] dp[i][j]表示走到第 i i i个问号时坐标为 j j j的概率.

状态转移方程 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] ∗ 0.5 + d p [ i − 1 ] [ j + 1 ] ∗ 0.5 dp[i][j]=dp[i-1][j-1]*0.5+dp[i-1][j+1]*0.5 dp[i][j]=dp[i1][j1]0.5+dp[i1][j+1]0.5.

因坐标可能为负,第二维加一个 B A S E = 10 BASE=10 BASE=10的偏移值即可.

代码III

const int MAXN = 25;  // 两倍空间
const int BASE = 10;  // 偏移量
string s1, s2;
double dp[MAXN][MAXN];  // dp[i][j]表示走到第i个问号时坐标为j的概率

void solve() {
	cin >> s1 >> s2;
	
	int pos1 = 0, pos2 = 0, cnt = 0;
	for (int i = 0; i < s1.length(); i++) {
		pos1 += s1[i] == '+' ? 1 : -1;

		if (s2[i] == '?') cnt++;
		else pos2 += s2[i] == '+' ? 1 : -1;
	}

	dp[0][pos2 + BASE] = 1;
	for (int i = 1; i <= cnt; i++) {
		for (int j = -10; j <= 10; j++)  // 枚举下标
			dp[i][j + BASE] = dp[i - 1][j - 1 + BASE] * 0.5 + dp[i - 1][j + 1 + BASE] * 0.5;
	}
	cout << fixed << setprecision(18) << dp[cnt][pos1 + BASE];
}

int main() {
	solve();
}


相关文章:

  • 【LC】反转链表, 相交链表, 环形链表
  • 【Java】之集合总结(上)
  • Redis中加锁的lua脚本的源码
  • Mac电脑解决Google翻译失效实用方法
  • 【易购管理系统】商品列表
  • 北斗导航 | RTKLib中的模型和算法(一)—— 时间系统
  • 【论文阅读】自动作文评分系统:一份系统的文献综述
  • avformat_open_input() 代码分析
  • Spring Bean的生命周期、Java配置BeanFactoryPostProcessor失效与解决
  • 大模型系统和应用——高效训练模型压缩
  • “华为杯”第十八届中国研究生数学建模竞赛一等奖经验分享
  • C#的StreamReader类使用说明
  • 基于图搜索的规划算法之 A* 家族(九):Hybrid A* 算法
  • 2022年Webpack 5初学者完整指南
  • 【MATLAB教程案例22】基于MATLAB图像去噪算法仿真——中值滤波、高斯滤波以及频域滤波等
  • [原]深入对比数据科学工具箱:Python和R 非结构化数据的结构化
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • HTTP中的ETag在移动客户端的应用
  • js操作时间(持续更新)
  • markdown编辑器简评
  • PV统计优化设计
  • Redis的resp协议
  • ubuntu 下nginx安装 并支持https协议
  • Vue2 SSR 的优化之旅
  • web标准化(下)
  • 彻底搞懂浏览器Event-loop
  • 和 || 运算
  • 基于HAProxy的高性能缓存服务器nuster
  • 记一次用 NodeJs 实现模拟登录的思路
  • 问题之ssh中Host key verification failed的解决
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (Java)【深基9.例1】选举学生会
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (三)c52学习之旅-点亮LED灯
  • (转)Windows2003安全设置/维护
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET 8.0 中有哪些新的变化?
  • .net Application的目录
  • .net framework4与其client profile版本的区别
  • .NET/C# 使用反射注册事件
  • .net操作Excel出错解决
  • .NET框架设计—常被忽视的C#设计技巧
  • .NET文档生成工具ADB使用图文教程
  • /使用匿名内部类来复写Handler当中的handlerMessage()方法
  • @AliasFor注解
  • @SpringBootApplication 包含的三个注解及其含义
  • [ 常用工具篇 ] POC-bomber 漏洞检测工具安装及使用详解
  • [ai笔记3] ai春晚观后感-谈谈ai与艺术
  • [Android] 修改设备访问权限
  • [C#]OpenCvSharp使用帧差法或者三帧差法检测移动物体
  • [c语言]小课堂 day2
  • [ERROR ImagePull]: failed to pull image k8s.gcr.io/kube-controller-manager失败