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

敬启,致那时的我

题面

题目描述

实乃理给你两个整数 \(S, k\),你需要帮她求出以下式子的值对 \(1,000,000,007\) 取模的结果:

\[\sum_{X = 0}^S [\mathrm{popc}(X) = k]F(X) \]

其中 \(F\) 为斐波那契数列,即 \(F(0) = F(1) = 1, F(n) = F(n - 1) + F(n - 2)\)\(\mathrm{popc}(X)\) 表示 \(X\) 的二进制表示中 \(1\) 的个数。

输入格式

第一行两个整数 \(n, k\)

第二行一个长度为 \(n\)\(01\)\(S_{2}\),代表 \(S\) 的二进制表示。保证 \(S_2\) 没有前导零。

输出格式

输出一行一个整数表示答案对 \(1,000,000,007\) 取模的结果。

输入输出样例 #1

输入 #1

3 0
110

输出 #1

1

输入输出样例 #2

输入 #2

3 1
110

输出 #2

8

输入输出样例 #3

输入 #3

3 2
110

输出 #3

24

输入输出样例 #4

输入 #4

17 8
11011111101010010

输出 #4

894224396

说明/提示

样例解释

对于样例一,答案为 \(F(0) = 1\)

对于样例二,答案为 \(F(1) + F(2) + F(4) = 1 + 2 + 5 = 8\)

对于样例三,答案为 \(F(3) + F(5) + F(6) = 3 + 8 + 13 = 24\)

数据范围

对于 \(100\%\) 的数据,\(0 \le k \le n \le 2 \times 10^3\)\(n, S \ge 1\)

子任务编号 特殊性质 分数
\(1\) A \(20\)
\(2\) B \(30\)
\(3\) C \(30\)
\(4\) \(20\)

特殊性质 A:\(S \le 10^6\)

特殊性质 B:\(k \le 2\)

特殊性质 C:\(S\) 可以表示为 \(2^y - 1\) 的形式,其中 \(y\) 是一个正整数。

题解

这道题发现是FIB序列,那这个FIB序列没啥好的性质,只能用矩阵乘法快速求出。

这道题开始通过特殊性质B,发现如果枚举两个一在哪里然后再去算矩阵快速幂这样是 \(O(n^3)\) 会超时,那我们发现快速幂这个东西本质不就是在每个二进制为一的时候去乘一下当前的阶乘吗?那我们就可以把快速幂数组预处理出来。那这样我们就不用每次去重新做一遍快速幂了。

那这个部分分启示我们要预处理快速幂数组,那我们考虑预处理完这个题目变成了什么别的形式,那现在这个题目变成了在这n个预处理出的快速幂元素中,选择k个相乘的和,那这个是好做的:设 \(f_{i,j}\) 表示前i个元素选了j个的乘积和。

那本题还要考虑是否超过了上界,那这个就写一个类似数位dp的东西,记录每一位是否已经达到上界即可。

最终状态设计:\(f_{i,j,0/1}\) 表示前i个元素选了j个是否到达上界的乘积和。

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 1e9 + 7;
struct MAT
{ll a[2][2];MAT operator*(const MAT &x) const{MAT c;c.a[0][0] = c.a[0][1] = c.a[1][0] = c.a[1][1] = 0;for (int k = 0; k < 2; k++){for (int i = 0; i < 2; i++){for (int j = 0; j < 2; j++){c.a[i][j] += a[i][k] * x.a[k][j] % mod;c.a[i][j] %= mod;}}}return c;}MAT operator+(const MAT &x) const{MAT c;c.a[0][0] = c.a[0][1] = c.a[1][0] = c.a[1][1] = 0;for (int i = 0; i < 2; i++){for (int j = 0; j < 2; j++){c.a[i][j] = (a[i][j] + x.a[i][j]) % mod;}}return c;}void print(){for (int i = 0; i < 2; i++){for (int j = 0; j < 2; j++){cout << a[i][j] << " \n"[j == 1];}}}
} base, bse, ksm[2005], f[2][2005][2], zro, fib;
int main()
{ios::sync_with_stdio(0), cin.tie(0);int n, K;cin >> n >> K;string s;cin >> s;// reverse(s.begin(), s.end());fib.a[0][0] = fib.a[0][1] = 1;fib.a[1][0] = fib.a[1][1] = 0;bse.a[0][0] = bse.a[1][1] = 1;bse.a[0][1] = bse.a[1][0] = 0;base.a[0][0] = base.a[0][1] = base.a[1][0] = 1;base.a[1][1] = 0;ksm[n - 1] = base;for (int i = n - 2; i >= 0; i--){base = base * base;ksm[i] = base;}int cur = 0, nxt = 1;f[cur][0][1] = bse;for (int i = 0; i < n; i++){for (int j = 0; j <= K; j++){for (int tt = 0; tt <= 1; tt++){f[nxt][j][tt] = zro;}}int bit = s[i] - '0';MAT MT = ksm[i];for (int j = 0; j <= K; j++){for (int tt = 0; tt <= 1; tt++){if (f[cur][j][tt].a[0][0] == 0 && f[cur][j][tt].a[0][1] == 0 && f[cur][j][tt].a[1][0] == 0 && f[cur][j][tt].a[1][1] == 0){continue;}int zd = 1;if (tt){zd = bit;}for (int tb = 0; tb <= zd; tb++){int ntt = (tt & (tb == zd));int nj = j + tb;if (nj > K){continue;}MAT nw = f[cur][j][tt];MAT nMT = nw * (tb ? MT : bse);f[nxt][nj][ntt] = f[nxt][nj][ntt] + nMT;}}}swap(cur, nxt);}cout << ((f[cur][K][0]).a[0][0] + (f[cur][K][1]).a[0][0]) % mod;return 0;
}
http://www.hskmm.com/?act=detail&tid=36078

相关文章:

  • 后量子密码学技术与标准化进程解析
  • 10月21日
  • 清楚标签默认样式,内容溢出盒子时的处理
  • 用 大模型 和 Gradio 构建一个 AI 反向词典
  • MySQL 事务
  • python概念详解
  • JAVA基础理解
  • 1279. 红绿灯路口
  • 软件工程第三次作业
  • 用户消费行为数据分析(随笔)
  • linux常用命令总结
  • sqlserver 主要的日期函数及用法示例
  • ICPC2022沈阳 游记(VP)
  • 大数据分析基础及应用案例:第四周学习报告——线性回归模型
  • 「LG7446-rfplca」题解
  • 图论刷题记录
  • 「LG6596-How Many of Them」题解
  • 骗我呢
  • 手写体识别
  • 你好,我是肆闲:C语言的学习,成长与分享旅程
  • AGC 合集 1.0
  • 20231302邱之钊密码系统设计实验一第二
  • 深入BERT内核:用数学解密掩码语言模型的工作原理
  • ZR 2025 NOIP 二十连测 Day 6
  • 20251021
  • [论文笔记] Precision-Guided Context Sensitivity for Pointer Analysis
  • 英语_备忘_疑难
  • 数学题刷题记录(数学、数论、组合数学)
  • 朋友圈文案不会写?这个AI指令可能帮得上忙
  • 「JOISC2020-掃除」题解