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

P1919 【模板】高精度乘法 | A*B Problem 升级版、P3803 【模板】多项式乘法(FFT)、P1595 信封问题(圆排列、错位排列)

P1919 【模板】高精度乘法 | A*B Problem 升级版(FFT算法)

题目描述

G42 快速傅里叶变换 FFT算法 高精度乘法 - 董晓 - 博客园 (cnblogs.com)

运行代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 3e6;
const double PI = acos(-1);struct complex {double x, y;complex operator+(const complex& t) const {return {x + t.x, y + t.y};}complex operator-(const complex& t) const {return {x - t.x, y - t.y};}complex operator*(const complex& t) const {return {x * t.x - y * t.y, x * t.y + y * t.x};}
};complex A[N], B[N];
char s1[N], s2[N];
int R[N], ans[N];// 交换两个复数
void swapComplex(complex& a, complex& b) {complex temp = a;a = b;b = temp;
}// 快速傅里叶变换
void FFT(complex A[], int n, int op) {for (int i = 0; i < n; ++i)R[i] = R[i / 2] / 2 + ((i & 1)? n / 2 : 0);for (int i = 0; i < n; ++i)if (i < R[i])swapComplex(A[i], A[R[i]]);for (int i = 2; i <= n; i <<= 1) {complex w1({cos(2 * PI / i), sin(2 * PI / i) * op});for (int j = 0; j < n; j += i) {complex wk({1, 0});for (int k = j; k < j + i / 2; ++k) {complex x = A[k], y = A[k + i / 2] * wk;A[k] = x + y;A[k + i / 2] = x - y;wk = wk * w1;}}}
}int main() {scanf("%s%s", s1, s2);int n = strlen(s1) - 1, m = strlen(s2) - 1;for (int i = 0; i <= n; i++)A[i].x = s1[n - i] - '0';for (int i = 0; i <= m; i++)B[i].x = s2[m - i] - '0';for (m = n + m, n = 1; n <= m; n <<= 1);FFT(A, n, 1);FFT(B, n, 1);for (int i = 0; i < n; ++i)A[i] = A[i] * B[i];FFT(A, n, -1);int k = 0, t = 0;for (int i = 0; i < n || t; i++) {t += A[i].x / n + 0.5;ans[k++] = t % 10;t /= 10;}while (k > 1 &&!ans[k - 1])k--;for (int i = k - 1; i >= 0; i--)printf("%d", ans[i]);return 0;
}

代码思路

  1. 首先定义了一个complex结构体来表示复数,并定义了复数的加法、减法和乘法运算。

  2. FFT函数实现快速傅里叶变换。通过计算R数组确定交换元素的位置,并进行位逆序交换。利用分治思想,对于不同长度的区间,通过旋转因子进行合并计算。

  3. main函数中:读取两个字符串s1s2,将它们转换为复数数组AB,其中每个复数的实部对应字符数字。确定合适的长度n进行快速傅里叶变换。对AB进行正变换、相乘,再进行逆变换。计算最终结果的进位和存储。从变换后的结果中逐步累加,并处理进位,将结果存储在ans数组中。去除前面多余的0,并输出最终结果。

P3803 【模板】多项式乘法(FFT)

题目描述

P3803 【模板】多项式乘法(FFT) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

运行代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#define LL long long
using namespace std;
const int N = 4e6;
const int g = 3, P = 998244353;int n, m, R[N];
LL A[N], B[N];LL qpow(LL a, LL b) {LL ans = 1;while (b) {if (b & 1) ans = ans * a % P;a = a * a % P;b >>= 1;}return ans;
}void swapLL(LL& a, LL& b) {LL temp = a;a = b;b = temp;
}void NTT(LL A[], int n, int op) {for (int i = 0; i < n; ++i)R[i] = R[i / 2] / 2 + ((i & 1) ? n / 2 : 0);for (int i = 0; i < n; ++i)if (i < R[i]) swapLL(A[i], A[R[i]]);for (int i = 2; i <= n; i <<= 1) {LL g1 = qpow(op == 1 ? g : qpow(g, P - 2), (P - 1) / i);for (int j = 0; j < n; j += i) {LL gk = 1;for (int k = j; k < j + i / 2; ++k) {LL x = A[k], y = gk * A[k + i / 2] % P;A[k] = (x + y) % P;A[k + i / 2] = (x - y + P) % P;gk = gk * g1 % P;}}}
}int main() {scanf("%d%d", &n, &m);for (int i = 0; i <= n; ++i) scanf("%lld", A + i);for (int i = 0; i <= m; ++i) scanf("%lld", B + i);for (m = n + m, n = 1; n <= m; n <<= 1);NTT(A, n, 1);NTT(B, n, 1);for (int i = 0; i < n; ++i) A[i] = A[i] * B[i] % P;NTT(A, n, -1);for (int i = 0; i <= m; ++i)printf("%d ", A[i] * qpow(n, P - 2) % P);return 0;
}

代码思路

NTT 是快速傅里叶变换(FFT)在数论中的一种类似应用。它利用了模运算和特定的原根来实现类似于 FFT 的分治和合并计算,以高效地计算多项式乘法。

在这段代码中,选择了 g = 3 作为原根,P = 998244353 作为模数。

思路

  1. qpow 函数用于快速计算模意义下的幂运算。

  2. NTT 函数实现了 NTT 过程。首先通过计算 R 数组来确定交换元素的位置,并进行位逆序交换。然后通过循环,对于不同长度的区间,利用原根计算出相应的系数,并进行合并计算。

  3. 在 main 函数中:读取两个多项式的系数。确定合适的长度 n 进行 NTT 计算。对两个多项式分别进行正变换。变换后的系数相乘。进行逆变换得到乘法结果。最后输出结果。

P1595 信封问题(圆排列、错位排列)

题目描述

P1595 信封问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

运行代码

#include<iostream>
using namespace std;
const int N=21;
long long D[N];
int main(){int n;cin>>n;D[1]=0,D[2]=1;for(int i=3; i<N; i++)D[i]=(i-1)*(D[i-1]+D[i-2]);  printf("%lld\n",D[n]);return 0;
}

代码思路

  1. 首先定义了一个常量N表示数列的最大长度,以及一个长整型数组D来存储数列的各项值。

  2. main函数中,首先读取一个整数n

  3. 初始化数列的前两项:D[1] = 0D[2] = 1

  4. 然后通过一个循环从第 3 项开始计算后续的每一项。计算方式为D[i] = (i - 1) * (D[i - 1] + D[i - 2])。这意味着每一项都是其前两项之和乘以当前项的索引减 1。

  5. 最后,输出数列的第n项的值D[n]

  6. D[i] = (i - 1) * (D[i - 1] + D[i - 2])为推断关系式

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 转行大模型成功进字节了!48k*15薪!
  • knowLedge-VueCLI项目中环境变量的定义与使用
  • 用C#实现连续打印pdf文件
  • 一起学习LeetCode热题100道(40/100)
  • LlamaIndex-milvus-RAG
  • 基于vue框架的yit商城uwd1i(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
  • 【产品经理】竞品分析怎么理解?拆解一下
  • 万字干货!手把手教你如何训练超大规模集群下的大语言模型
  • 【STM32嵌入式系统设计与开发拓展】——15_ADC
  • 重修设计模式-行为型-状态模式
  • Java面试八股之什么是消息队列
  • 智慧景区系统:科技赋能旅游新体验
  • 理解 Go 语言的分组操作
  • JAVA中的ArrayDeque和LinkedList实现Deque,前者不能存NULL结点,后者可以存放NULL。
  • 【upload]-ini-[SUCTF 2019]CheckIn-笔记
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • 03Go 类型总结
  • Android开源项目规范总结
  • CSS实用技巧
  •  D - 粉碎叛乱F - 其他起义
  • ES6 学习笔记(一)let,const和解构赋值
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • js操作时间(持续更新)
  • k8s如何管理Pod
  • LintCode 31. partitionArray 数组划分
  • oschina
  • Phpstorm怎样批量删除空行?
  • React 快速上手 - 07 前端路由 react-router
  • React16时代,该用什么姿势写 React ?
  • React的组件模式
  • Service Worker
  • Terraform入门 - 3. 变更基础设施
  • Vue实战(四)登录/注册页的实现
  • Webpack4 学习笔记 - 01:webpack的安装和简单配置
  • 给初学者:JavaScript 中数组操作注意点
  • 力扣(LeetCode)357
  • 前端性能优化——回流与重绘
  • 数据可视化之 Sankey 桑基图的实现
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • 在Docker Swarm上部署Apache Storm:第1部分
  • C# - 为值类型重定义相等性
  • SAP CRM里Lead通过工作流自动创建Opportunity的原理讲解 ...
  • scrapy中间件源码分析及常用中间件大全
  • # 数仓建模:如何构建主题宽表模型?
  • #define与typedef区别
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • $.ajax()参数及用法
  • (LeetCode) T14. Longest Common Prefix
  • (备忘)Java Map 遍历
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (附源码)ssm码农论坛 毕业设计 231126
  • (十)Flink Table API 和 SQL 基本概念
  • (游戏设计草稿) 《外卖员模拟器》 (3D 科幻 角色扮演 开放世界 AI VR)
  • .gitignore文件—git忽略文件
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?