首页 > 其他分享 >CF717A Festival Organization 题解

CF717A Festival Organization 题解

时间:2024-09-10 16:02:34浏览次数:7  
标签:Node kMod return Festival 题解 ret int bs CF717A

Description

一个合法的串定义为:长度在 \([l,r]\) 之间,且只含 0,1,并且不存在连续 \(2\) 个或更多的 \(0\)。

现在要选出 \(k\) 个长度相同的合法的串,问有几种选法,答案模 \(10^9+7\)。

\(1\leq k\leq 200,1\leq l\leq r\leq 10^{18}\)。

Solution

容易发现答案为 \(\sum_{i=l+2}^{r+2}{\binom{Fib_i}{k}}\)。先将 \(l,r\) 都加 \(2\),题目就转化为了求 \(\sum_{i=l}^{r}{Fib_i^{\underline{k}}}\)。

注意到下降幂是不好做区间求和的,考虑用第一类斯特林数转化为普通幂:

\[x^{\underline{k}}=\sum_{i=0}^{k}{(-1)^{k-i}{k\brack i}x^i} \]

于是题目相当于是求斐波那契数列的 \(k\) 次区间和。

但是斐波那契数列的 \(k\) 次区间和仍然是无法做的,注意到等比数列是可以求区间和的,所以可以用通项公式将斐波那契数转化成幂次再求和:

\[\begin{aligned} Fib_i^k&=\left[\left(\frac{1+\sqrt 5}{2}\right)^i-\left(\frac{1-\sqrt 5}{2}\right)^i\right]^k\\ &=\sum_{j=0}^{i}{\binom{i}{j}\left(\frac{1+\sqrt 5}{2}\right)^{ij}\left(\frac{1-\sqrt 5}{2}\right)^{i(k-j)}}\\ &=\sum_{j=0}^{i}{\binom{i}{j}\left[\left(\frac{1+\sqrt 5}{2}\right)^{j}\left(\frac{1-\sqrt 5}{2}\right)^{k-j}\right]^i} \end{aligned} \]

这样就可以做了。但是有个问题,就是 \(\sqrt 5\) 在 \(\bmod 10^9+7\) 意义下没有定义,所以需要维护一个形如 \(a+b\sqrt 5\) 的类。

注意等比数列的比为 \(1\) 的情况要特判。

时间复杂度:\(O(k^2\log r)\)。

Code

#include <bits/stdc++.h>

#define int int64_t

const int kMaxK = 205, kMod = 1e9 + 7, kInv2 = 500000004, kInv5 = 400000003;

int k, l, r;
int C[kMaxK][kMaxK], S[kMaxK][kMaxK], fac[kMaxK], ifac[kMaxK];

constexpr int qpow(int bs, int64_t idx = kMod - 2) {
  int ret = 1;
  for (; idx; idx >>= 1, bs = (int64_t)bs * bs % kMod)
    if (idx & 1)
      ret = (int64_t)ret * bs % kMod;
  return ret;
}

inline int add(int x, int y) { return (x + y >= kMod ? x + y - kMod : x + y); }
inline int sub(int x, int y) { return (x >= y ? x - y : x - y + kMod); }
inline void inc(int &x, int y) { (x += y) >= kMod ? x -= kMod : x; }
inline void dec(int &x, int y) { (x -= y) < 0 ? x += kMod : x; }

int getop(int x) { return (~x & 1) ? 1 : (kMod - 1); }

struct Node {
  int a, b; // a + b * sqrt(5)

  Node(int _a = 0, int _b = 0) : a(_a), b(_b) {}

  Node inv() {
    int k = qpow(sub(1ll * a * a % kMod, 5ll * b % kMod * b % kMod));
    return {1ll * a * k % kMod, 1ll * sub(0, b) * k % kMod};
  }

  friend bool operator ==(Node a, Node b) { return a.a == b.a && a.b == b.b; }
  friend Node operator +(Node a, Node b) { return {add(a.a, b.a), add(a.b, b.b)}; }
  friend Node operator -(Node a, Node b) { return {sub(a.a, b.a), sub(a.b, b.b)}; }
  friend Node operator *(Node a, Node b) { return {add(1ll * a.a * b.a % kMod, 5ll * a.b % kMod * b.b % kMod), add(1ll * a.a * b.b % kMod, 1ll * a.b * b.a % kMod)}; }
  friend Node operator /(Node a, Node b) { return a * b.inv(); }
  friend Node operator -(Node a) { return {sub(0, a.a), sub(0, a.b)}; }
};

Node qpow(Node bs, int idx) {
  Node ret = {1, 0};
  for (; idx; idx >>= 1, bs = bs * bs)
    if (idx & 1)
      ret = ret * bs;
  return ret;
}

int getsum(int n, int k) {
  if (!n) return 0;
  Node ret = {0, 0}, a = {kInv2, kInv2}, b = {kInv2, sub(0, kInv2)};
  for (int i = 0; i <= k; ++i) {
    Node bs = qpow(a, i) * qpow(b, k - i), sum = {0, 0};
    if (bs == (Node){1, 0}) sum = {n % kMod, 0};
    else sum = (qpow(bs, n + 1) - bs) / (bs - (Node){1, 0});
    if (~(k - i) & 1) ret = ret + sum * (Node){C[k][i], 0};
    else ret = ret - sum * (Node){C[k][i], 0};
  }
  if (~k & 1) return 1ll * ret.a * qpow(kInv5, k / 2) % kMod;
  else return 1ll * ret.b * qpow(kInv5, k / 2) % kMod;
}

int getsum(int l, int r, int k) {
  return sub(getsum(r, k), getsum(l - 1, k));
}

void prework() {
  fac[0] = ifac[0] = C[0][0] = S[0][0] = 1, 1;
  for (int i = 1; i <= 200; ++i) {
    C[i][0] = 1;
    fac[i] = 1ll * i * fac[i - 1] % kMod;
    ifac[i] = qpow(fac[i]);
    for (int j = 1; j <= i; ++j) {
      C[i][j] = add(C[i - 1][j - 1], C[i - 1][j]);
      S[i][j] = add(S[i - 1][j - 1], 1ll * (i - 1) * S[i - 1][j] % kMod);
    }
  }
}

void dickdreamer() {
  prework();
  std::cin >> k >> l >> r;
  l += 2, r += 2;
  int ans = 0;
  for (int i = 0; i <= k; ++i) {
    inc(ans, 1ll * S[k][i] * getop(k - i) % kMod * getsum(l, r, i) % kMod);
  }
  std::cout << 1ll * ans * ifac[k] % kMod << '\n';
}

int32_t main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int T = 1;
  // std::cin >> T;
  while (T--) dickdreamer();
  // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
  return 0;
}

标签:Node,kMod,return,Festival,题解,ret,int,bs,CF717A
From: https://www.cnblogs.com/Scarab/p/18406589

相关文章

  • 【Py/Java/C++三种语言OD独家2024E卷真题】20天拿下华为OD笔试之【回溯】2024E-字符串
    可上欧弟OJ系统练习华子OD、大厂真题绿色聊天软件戳od1441了解算法冲刺训练(备注【CSDN】否则不通过)文章目录相关推荐阅读题目描述与示例题目描述输入描述输出描述示例一输入输出说明示例二输入输出说明解题思路代码pythonjavacpp时空复杂度华为OD算法/大厂面......
  • Android中SurfaceView的双缓冲机制和普通View叠加问题解决办法
    本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点SurfaceView是Android平台上用于高效渲染图形的视图控件。它将内容绘制在一个独立的Surface上,可以直接由渲染线程访问,从而提高性能,尤其是在需要频繁刷新和更新......
  • 题解:CF913C Party Lemonade
    分析因为容量为\(2^{i-1}\),所以对于任意的\(i<j\),第\(j\)种瓶子一定可以通过选择\(2^{j-i}\)个\(i\)种瓶子来实现。定义一个瓶子的性价比为\(\dfrac{\textrm{容量}}{\textrm{价格}}\),即\(\dfrac{2^{i-1}}{c_i}\)。我们可以按照每个瓶子的性价比从高到低排序,依次选择......
  • 题解:CF913D Too Easy Problems
    题意给定一场考试,考试会持续\(T\)毫秒,由\(n\)道题目组成,你可以用\(t_i\)毫秒解决第\(i\)个问题,每个问题给定一个整数\(a_i\)。要求你选出一个试题集合\(S\),若该集合大小为\(k\),它应满足\(T\geq\sum_{i\inS}\limitst_i\),你需要最大化\(\sum_{i\inS}\limits[a_i......
  • 题解:P5618 [SDOI2015] 道路修建
    题意给定一个\(2\timesN\)的网格,网格上的点和上下左右连边。要求支持以下几种操作:修改某条边的边权。求满足\(y\in[l,r]\)的点构成的点集的最小生成树。分析这道题的想法和P4246[SHOI2008]堵塞的交通很相似。注意到\(N,M\leq6\times10^4\),并且查询的是......
  • 题解:P6089 [JSOI2015] 非诚勿扰
    分析首先我们要求出对于第\(i\)位女性,她选择每个列表中的男性的概率是多少。第一轮选择第一位的概率为\(p\),选择第二位的概率为\(p(1-p)\),以此类推。显然第一轮选择第\(k\)位的概率为\(p(1-p)^{k-1}\)。假设列表中有\(n\)名男性,那么第二轮选择第一位的概率为\(p(1-p......
  • 题解:P3968 [TJOI2014] 电源插排
    题意维护一个\(01\)串,初始均为\(0\),支持:单点将\(1\)修改为\(0\)。查询区间中\(1\)的个数。查询最长且最靠右的连续\(0\)段的靠右的中点,并将其改为\(1\)。分析第一个操作和第二个操作显然使用动态开点线段树维护。我们只需要解决第三个操作。我们用平衡树存储......
  • CF1621G Weighted Increasing Subsequences 题解
    题目链接点击打开链接题目解法这种题就感觉每一步都不难想,但串在一起就不会显然考虑位置\(x\)作为\(lis\)的一部分,合法的\(lis\)的个数合法的约束是:令\(lis\)的最后一个位置为\(last\),满足\(\max\{a_{last+1},...,a_n\}>a_x\)不难发现,合法的\(last\)是一段区间......
  • 【最新华为OD机试E卷-支持在线评测】通过软盘拷贝文件(200分)多语言题解-(Python/C/Ja
    ......
  • P7230 题解
    P7230思路对每个左端点维护右端点\(res_i\)。操作形如删去一个数再加入一个数。如果删掉\(p\)上的\(a_p\),找到左右最近的\(l,r\)使得\(a_l=a_r=a_p\)。那么\(res_{l+1},\dotsb,res_p\)对\(r\)取max。实际上要维护\(\maxres_i-i+1\),因为\(res_i\)单调,所以相当于......