[生成函数][DFT][NTT] Hdu P6067 Big Integer

题解

代码

 1 #include <cstdio>
 2 #include <istream>
 3 #define ll long long
 4 using namespace std;
 5 const ll N=200010,mo=786433;
 6 int T,n,m,k,x,y,sum,num[N],f[N],len,L,rev[N],v[10][N];
 7 ll a[10][N],inv[mo],fac[N],ny[N],ans[N],p[N],P[N];
 8 char s[N];
 9 ll ksm(ll a,ll b) { ll r=1; for (;b;b>>=1,a=a*a%mo) if (b&1) r=r*a%mo; return r; }
10 void ntt(ll *a,int len,int f)
11 {
12     for (int i=0;i<len;i++) if (rev[i]>i) swap(a[i],a[rev[i]]);
13     for (int i=2;i<=len;i<<=1)
14     {
15         ll r,m=i>>1;
16         if (f==1) r=p[i]; else r=P[i];
17         for (int j=0;j<len;j+=i)
18         {
19             ll R=1;
20             for (int k=0;k<m;k++,R=R*r%mo)
21             {
22                 ll x=a[j+k],y=a[j+k+m]*R%mo;
23                 a[j+k]=(x+y)%mo,a[j+k+m]=(x-y+mo)%mo;
24             }
25         }
26     }
27     if (f==-1) { ll r=ksm(len,mo-2); for (int i=0;i<len;i++) a[i]=a[i]*r%mo; }
28 }
29 int main()
30 {
31
32     fac[0]=ny[0]=1;
33     for (int i=1;i<N;i++) p[i]=ksm(10,(mo-1)/i),P[i]=ksm(p[i],mo-2);
34     for (int i=0;i<mo;i++) inv[i]=ksm(i,mo-2);
35     for (int i=1;i<N;i++) fac[i]=fac[i-1]*(ll)i%mo;
36     ny[N-1]=ksm(fac[N-1],mo-2);
37     for (int i=N-2;i;i--) ny[i]=ny[i+1]*(ll)(i+1)%mo;
38     scanf("%d",&T);
39     while (T--)
40     {
41         scanf("%d%d%d",&n,&m,&k),n--,sum=0;
42         for (int i=0;i<n;i++)
43         {
44             scanf("%s",s);
45             for (int j=0;j<=m;j++) v[i][j]=s[j]-‘0‘;
46         }
47         for (len=1,L=-1;len<=n*m;len*=2) L++;
48         for (int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<L);
49         for (int i=0;i<len;i++) num[i]=0,f[i]=1;
50         for (int i=0;i<n;i++)
51         {
52             for (int j=0;j<len;j++) a[i][j]=0;
53             for (int j=0;j<=m;j++) if (v[i][j]) a[i][j]=ny[j];
54             ntt(a[i],len,1);
55             for (int j=0;j<len;j++) if (a[i][j]) f[j]=f[j]*a[i][j]%mo; else num[j]++;
56         }
57         for (int i=0;i<len;i++) ans[i]=num[i]?0:f[i];
58         for (int x,y;k;k--)
59         {
60             scanf("%d%d",&x,&y),x--;
61             for (int i=0;i<len;i++) if (a[x][i]) f[i]=f[i]*inv[a[x][i]]%mo; else num[i]--;
62             ll flag;
63             if (v[x][y]==1) flag=-1; else flag=1;
64             v[x][y]^=1;
65             ll r=1,R=ksm(p[len],y);
66             for (int i=0;i<len;i++,r=r*R%mo) a[x][i]=(a[x][i]+flag*inv[fac[y]]*r%mo+mo)%mo;
67             for (int i=0;i<len;i++) if (a[x][i]) f[i]=f[i]*a[x][i]%mo; else num[i]++;
68             for (int i=0;i<len;i++) ans[i]=(ans[i]+(num[i]?0:f[i]))%mo;
69         }
70         ntt(ans,len,-1);
71         for (int i=1;i<len;i++) sum=(sum+ans[i]*fac[i]%mo)%mo;
72         printf("%lld\n",sum);
73     }
74 }

原文地址:https://www.cnblogs.com/Comfortable/p/11364236.html

时间: 2024-11-09 07:01:16

[生成函数][DFT][NTT] Hdu P6067 Big Integer的相关文章

HDU 6441 - Find Integer - [费马大定理][2018CCPC网络选拔赛第4题]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6441 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Descriptionpeople in USSS love math very much, and there is a famous math problem .give you two integers n,a,

BZOJ[3992][SDOI2015]序列统计 生成函数+NTT

首先了解一下指标 看我瞎bb也可以 因为原根\(g\)满足\(g^i,g^j(i,j\in (1,MOD-1),i\neq j)\)互不相同 则可以给每个数\(i\)定义一个指标\(ind_i\)表示模意义下的\(\log_g i\),并且在区间\([1,\varphi(MOD)]\)中是互不相同的 和\(log\)类似,指标也满足\(ind_{i*j}\equiv ind_i+ind_j\)就可以把乘法弄成加法了 题目要求的\((a×b)mod M=x\)等价于\((ind[a]+ind[b]

PKUWC2019垫底记

凭着noip2018中超凡的运气,我来到了纪中. DAY0 听说PKUWC可以看榜?那就不用担心写挂啦!开心! 刚从雅礼回来休息了一天,下午就和hz一起坐上教练的车去到了中山纪中. 纪中好大好漂亮啊!校园里红墙绿瓦,潺潺兰溪,怒放茶花,绿荫小道,湖平如镜.(摘自纪中官网) 然而一到宿舍心态就崩了.这枕头被子为什么这么一股奇怪的味道啊!!问了下不明真相的门卫能不能换,他啥也不知道,我也找不到组委会的人.这还让不让人睡觉了!! 不管了,希望能把住酒店的人的被子换过来. 试机: T1填空题,写俩循环暴

HDU 1171 Big Event in HDU --暴力+生成函数

题意:给n种房子,每种房子有一个值val和个数cnt,现在要把这些房子分成两部分,争取两部分总值相等,如果不能相等,让A>B,且A-B最小. 解法:先跑一次生成函数,c[n]表示组成总值为n的方法种数,然后从Total/2~0枚举B的总值,如果c[i]不为0,说明可以达到 i 这个状态,说明这就是B的最接近A的值(因为最接近Total/2).算法复杂度较高.跑了1600多ms,不知道还有没有更优的算法. 代码: #include <iostream> #include <cstdi

HDU 2189 悼念512汶川大地震遇难同胞――来生一起走 --生成函数

这题跟上两题也差不多. 把150以内的素数找出来,把素数的值看做硬币的面值,每个硬币的个数即ceil(150/prime[i]),因为再多也没用,最多组成n=150就行了,所以又回到了找硬币问题.用生成函数解之. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std

hdu acm-1047 Integer Inquiry(大数相加)

Integer Inquiry Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 11678    Accepted Submission(s): 2936 Problem Description One of the first users of BIT's new supercomputer was Chip Diller. He ex

Minimum Integer sequence HDU - 3522(扩展KMP)

Minimum Integer sequence HDU - 3522 题意: 几行代码看了一个多小时!!吐血!! 明天再来补题~ 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=100010; 4 char s[maxn],t[maxn]; 5 int lens,lent; 6 int nex[maxn],ex[maxn]; 7 int best; 8 9 void getnex(char* t){ 10

HDU 1028 Ignatius and the Princess III(生成函数)

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 24796    Accepted Submission(s): 17138 Problem Description "Well, it seems the first problem is too easy. I will let you know how foolish you are

HDU Integer&#39;s Power(容斥原理)

题意 求[l,r]的最大指数和(1<=l,r<=10^18) 最大指数和(如64=8^2=4^3=2^6,所以64的最大指数和是6) 题解 很明显我们可以先求出[1,n]的最大指数和,然后再作差. 我们可以先求出num[i]代表[1,n]中最大指数为i的数有多少个. 然后枚举全部的i,然后让答案加上i*num[i]: 那么怎么求num[i]呢 我们可以求出[1,n]中指数为x的数有多少个作为num[x]的初步值.这个用n1/x就可以求出(不过要注意精度问题,及其恶心,看代码吧) 然后这个num