(以下以$B$为进制,$m$为幂次,$n=B^{m}$)

定义$\oplus$为$k$进制下不进位加法,$\otimes$为$\oplus$卷积

令$f_{i,j}$表示前$i$个数的$\oplus$之和为$j$的子序列数,再令$g_{i,j}=[j=0]+[j=a_{i}]$($a_{i}$为给定序列),则$f_{i}=f_{i-1}\otimes g_{i}$

类似uoj272,但以该题复杂度计算时间复杂度显然是不对的

根据$g_{i,j}$的式子,不难发现将其做了DFT后的结果显然恰好就是矩阵$A$的第0行加第$a_{i}$行

直接考虑最终将每一个$g_{i}$的DFT对应位置相乘后第$j$个位置的值,即$ans_{j}=\prod_{i=1}^{n}(A_{0,j}+A_{a_{i},j})$

不难发现$A_{i,j}=\omega^{k}$(指存在$k$,其中$0\le k<B$),我们如果能知道$A_{a_{i},j}$中每一个$k$出现了多少次,再使用快速幂来计算,就可以做到$o(B\log_{2}n)$的复杂度了

更具体的,用$f_{i,j}$表示有多少个$k$满足$A_{a_{k},i}=\omega^{j}$,答案即$ans_{j}=\prod_{i=0}^{B-1}(1+\omega^{i})^{f_{j,i}}$($A_{0,j}=1$)

如何求出$f_{i,j}$,其并不容易递推,考虑这样一个构造:对于每一个$i$,求出$f_{i}$这个长度为$B$的序列DFT的结果,再用IDFT即求出$f_{i,j}$

考虑这个DFT结果的第$k$个数,即$\sum_{l=0}^{B-1}f_{i,l}A_{l,k}=\sum_{l=0}^{B-1}f_{i,l}(\omega^{l})^{k}=\sum_{l=0}^{n-1}(A_{a_{l},i})^{k}$

再构造一个$C_{i}=\sum_{j=0}^{n-1}[a_{j}=i]$,那么对$C$做DFT后的第$i$项即为$\sum_{j=0}^{n-1}C_{j}A_{j,i}=\sum_{j=0}^{n-1}A_{a_{j},i}$

其实这两个式子很接近,只需要让每一个$A_{i,j}$都变为其$k$次幂即可

注意到我们能快速计算DFT依赖于第二个性质($A_{i,j}=A_{\lfloor\frac{i}{B}\rfloor,\lfloor\frac{j}{B}\rfloor}A_{i\ mod\ B,j\ mod\ B}$),而在这个性质下,让每一个$A_{i,j}$都变为其$k$次幂等价于构造$A$左上角的$B\times B$的部分为$A_{i,j}=\omega^{ijk}$

具体来说,分为以下四个步骤:

1.对$C$做$B$次DFT,每一次DFT的$A$矩阵不同,第$k(0\le k<B)$次DFT的$A_{i,j}=\omega^{ijk}(0\le i,j<B)$,这里的时间复杂度是$o(mB^{m+4})$(由于两数相乘复杂度也为$o(B^{2})$,一次DFT复杂度为$o(mB^{m+3})$)

2.对于第一步中第$i$次DFT结果的第$j$项,恰好就是$f_{j}$(这是一个长为$B$的数列)做DFT后的第$i$项,换言之我们得到了每一个$f_{j}$做DFT后的结果,做$n$次$B^{4}$的IDFT即可,复杂度为$o(B^{m+4})$

3.得到$f_{i,j}$后,直接根据$ans_{j}=\prod_{i=0}^{B-1}(1+\omega^{i})^{f_{j,i}}$计算出$ans_{j}$,通过快速幂来优化,那么求一个$ans_{j}$的时间复杂度为$o(B^{3}\log_{2}n)$,总复杂度即$o(B^{m+3}\log_{2}n)$

4.求出$ans_{j}$再做一次IDFT即为答案,时间复杂度为$o(mB^{m+3})$

最终总复杂度为$o((m+\log_{2}n)B^{m+4})$,可以通过

另外关于数值的表示,在平常递归时先使用$\sum_{i=0}^{B-1}a_{i}\omega^{i}$来表示,根据$\omega^{B}=1$可以对其封闭运算,当我们可以证明某一个数为实数且需要得到该值时,通过如下方式降幂,然后$\omega^{0}$系数即为答案

降幂的需要对$B$分类:

1.若$B=5$,将$\omega^{4}$利用$\sum_{i=0}^{4}\omega^{i}=\frac{1-\omega^{5}}{1-\omega}=0$来降幂

2.若$B=6$,根据$\omega^{3}=-1$来降幂,首先得到$\omega^{i}=-\omega^{i-\frac{B}{2}}$来将$i$次项($\frac{B}{2}\le i<B$)降幂,再利用$\sum_{i=0}^{2}(-\omega)^{i}=\frac{1-(-\omega)^{3}}{1+\omega}=0$来降$\omega^{2}$

关于这个降幂的正确性(也就是之后高次项不能将虚数部分抵消)不会证,但可以发现其等价于不能再次进行降幂,之后(观察)发现找不到继续降的方式,即合法

(注意输入是$B$进制)

  1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 100005
4 #define M 7
5 #define maxB 6
6 #define mod 998244353
7 int n,m,x,B,base[N][M];
8 struct Complex{
9 int a[maxB];
10 Complex(){
11 memset(a,0,sizeof(a));
12 }
13 Complex(int x){
14 memset(a,0,sizeof(a));
15 a[0]=x;
16 }
17 Complex(int x,int y){
18 memset(a,0,sizeof(a));
19 a[0]=x,a[1]=y;
20 }
21 Complex operator + (const Complex &k)const{
22 Complex o;
23 for(int i=0;i<B;i++)o.a[i]=(a[i]+k.a[i])%mod;
24 return o;
25 }
26 Complex operator * (const Complex &k)const{
27 Complex o;
28 for(int i=0;i<B;i++)
29 for(int j=0;j<B;j++)o.a[(i+j)%B]=(o.a[(i+j)%B]+1LL*a[i]*k.a[j])%mod;
30 return o;
31 }
32 int get(){
33 if (B==5)return (a[0]-a[4]+mod)%mod;
34 return ((a[0]-a[3]+mod)%mod-(a[2]-a[5]+mod)%mod+mod)%mod;
35 }
36 }inv,A[maxB][maxB],AA[maxB][maxB],invA[maxB][maxB],a[N],b[maxB][N],f[N][maxB];
37 int read(){
38 int x=0;
39 char c=getchar();
40 while ((c<'0')||(c>'9'))c=getchar();
41 while ((c>='0')&&(c<='9')){
42 x=x*B+c-'0';
43 c=getchar();
44 }
45 return x;
46 }
47 Complex pow(Complex n,int m){
48 Complex s=n,ans=Complex(1);
49 while (m){
50 if (m&1)ans=ans*s;
51 s=s*s;
52 m>>=1;
53 }
54 return ans;
55 }
56 void DFT(Complex *a){
57 Complex aa[B];
58 for(int i=0,s=1;i<m;i++,s*=B)
59 for(int j=0;j<n;j++)
60 if (!base[j][i]){
61 for(int k=0;k<B;k++)aa[k]=Complex();
62 for(int k=0;k<B;k++)
63 for(int l=0;l<B;l++)aa[k]=aa[k]+a[j+l*s]*A[l][k];
64 for(int k=0;k<B;k++)a[j+k*s]=aa[k];
65 }
66 }
67 void IDFT(Complex *a){
68 Complex aa[B];
69 for(int i=0,s=1;i<m;i++,s*=B)
70 for(int j=0;j<n;j++)
71 if (!base[j][i]){
72 for(int k=0;k<B;k++)aa[k]=Complex();
73 for(int k=0;k<B;k++)
74 for(int l=0;l<B;l++)aa[k]=aa[k]+a[j+l*s]*invA[l][k];
75 for(int k=0;k<B;k++)a[j+k*s]=aa[k];
76 }
77 }
78 int main(){
79 scanf("%d%d%d",&n,&B,&m);
80 for(int i=0;i<n;i++){
81 x=read();
82 a[x]=a[x]+Complex(1);
83 }
84 n=1;
85 for(int i=0;i<m;i++)n*=B;
86 for(int i=0;i<n;i++){
87 base[i][0]=i%B;
88 for(int j=1;j<m;j++)base[i][j]=base[i/B][j-1];
89 }
90 inv=pow(Complex(B),mod-2);
91 for(int i=0;i<B;i++)
92 for(int j=0;j<B;j++){
93 A[i][j]=Complex(1);
94 AA[i][j]=pow(Complex(0,1),i*j);
95 invA[i][j]=pow(Complex(0,1),B*B-i*j)*inv;
96 }
97 for(int i=0;i<B;i++){
98 memcpy(b[i],a,sizeof(a));
99 DFT(b[i]);
100 for(int j=0;j<B;j++)
101 for(int k=0;k<B;k++)A[j][k]=A[j][k]*AA[j][k];
102 }
103 for(int i=0;i<n;i++)
104 for(int j=0;j<B;j++)
105 for(int k=0;k<B;k++)f[i][j]=f[i][j]+b[k][i]*invA[k][j];
106 for(int i=0;i<n;i++){
107 a[i]=Complex(1);
108 for(int j=0;j<B;j++)a[i]=a[i]*pow(pow(Complex(0,1),j)+Complex(1),f[i][j].get());
109 }
110 IDFT(a);
111 for(int i=0;i<n;i++)printf("%d\n",a[i].get());
112 }

[luogu5577]算力训练的更多相关文章

  1. 百度ERNIE 2.0强势发布!16项中英文任务表现超越BERT和XLNet

    2019年3月,百度正式发布NLP模型ERNIE,其在中文任务中全面超越BERT一度引发业界广泛关注和探讨. 今天,经过短短几个月时间,百度ERNIE再升级.发布持续学习的语义理解框架ERNIE 2. ...

  2. 星际争霸的虫王IA退役2年搞AI,自叹不如了

    ------------恢复内容开始------------ 金磊 发自 凹非寺 量子位|公众号 QbitA 这年头,直播讲AI,真算不上什么新鲜事.但要是连职业电竞选手,都开播主讲呢?没开玩笑,是真 ...

  3. YOLO 从数据集制作到训练

    1.图片数据集收集 共 16种 集装箱船 container ship 散货船 bulker 油船 tanker 游轮 / 客轮 / 邮轮 passenger liner 渔船 fishing boa ...

  4. ubuntu16.04安装tensorflow-gpu和cuda8.0加速训练

    转载请注明出处:http://www.cnblogs.com/buxizhizhoum/p/8086230.html 环境: 系统:ubuntu 16.04 cpu:i5 gpu:gt920m mem ...

  5. 华为云Volcano:让企业AI算力像火山一样爆发

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动",获取华 ...

  6. 学习AI之NLP后对预训练语言模型——心得体会总结

    一.学习NLP背景介绍:      从2019年4月份开始跟着华为云ModelArts实战营同学们一起进行了6期关于图像深度学习的学习,初步了解了关于图像标注.图像分类.物体检测,图像都目标物体检测等 ...

  7. AI本质就是“暴力计算”?看华为云如何应对算力挑战

    随着AI人工智能技术的飞速发展,相关的AI应用场景已经拓宽至各行各业.你可能想象不到的是,现在大家手上的智能手机的运算能力,甚至比美国航空航天局1969年登月计划中最先进计算机还高出几百上千万倍乃至更 ...

  8. 转pytorch中训练深度神经网络模型的关键知识点

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_42279044/articl ...

  9. 【转载】BERT:用于语义理解的深度双向预训练转换器(Transformer)

    BERT:用于语义理解的深度双向预训练转换器(Transformer)   鉴于最近BERT在人工智能领域特别火,但相关中文资料却很少,因此将BERT论文理论部分(1-3节)翻译成中文以方便大家后续研 ...

随机推荐

  1. 记一次 .NET 某电商定向爬虫 内存碎片化分析

    一:背景 1. 讲故事 上个月有位朋友wx找到我,说他的程序存在内存泄漏问题,寻求如何解决? 如下图所示: 从截图中可以看出,这位朋友对 windbg 的操作还是有些熟悉的,可能缺乏一定的实操经验,所 ...

  2. Vue3学习(八)之 Vue CLI多环境配置

    一.前言 这里相对于之前就没那么麻烦了,通俗点说就是使用配置文件来管理多环境,实现环境的切换. 二.实现切换 1.增加开发和生产配置文件 在web的根目录下,创建开发环境切换配置文件.env.dev, ...

  3. kivy布局(一)

    # import kivy from kivy.app import App # 导入应用 from kivy.uix.label import Label # 导入标签 from kivy.uix. ...

  4. [Beta]the Agiles Scrum Meeting 2

    会议时间:2020.5.11 20:00 1.每个人的工作 今天已完成的工作 成员 已完成的工作 yjy 修复bug将自动评测改为异步HTTP请求 tq 实现查看.删除测试点功能的后端将自动评测改为异 ...

  5. 并发编程从零开始(八)-ConcurrentHashMap

    并发编程从零开始(八)-ConcurrentHashMap 5.5 ConcurrentHashMap HashMap通常的实现方式是"数组+链表",这种方式被称为"拉链 ...

  6. 阿里Nacos部署

    Nacos的部署 一.单机部署 **4.修改 Nacos 存储为 Mysql** 二.集群部署 1.机器部署列表 2.修改 `nacos/conf/application.properties`中的端 ...

  7. 基于websocket实现的一个简单的聊天室

    本文是基于websocket写的一个简单的聊天室的例子,可以实现简单的群聊和私聊.是基于websocket的注解方式编写的.(有一个小的缺陷,如果用户名是中文,会乱码,不知如何处理,如有人知道,请告知 ...

  8. linux shell 基本语法之快速上手shell编程

    从程序员的角度来看, Shell本身是一种用C语言编写的程序,从用户的角度来看,Shell是用户与Linux操作系统沟通的桥梁.用户既可以输入命令执行,又可以利用 Shell脚本编程,完成更加复杂的操 ...

  9. 攻防世界 杂项 3.神奇的Modbus

    [目标] 了解modbus协议 [工具] Wireshark [分析过程] 在数据包中寻找flag就行,flag是明文形式存储. 工业设备消息传输使用modbus协议.所以我就采集了modbus的通信 ...

  10. 小白自制Linux开发板 九. 修改开机Logo

    许久不见啊,今天我们继续来修改我们的系统. 通过前面的几篇文章我们已经能轻松驾驭我们的开发板了,但是现在都是追求个性化的时代,我们在开发板上打上了自己的Logo,那我们是否可以改变开机启动的Logo呢 ...