[UOJ182]a^-1 + b problem
$\newcommand{\align}[1]{\begin{align*}#1\end{align*}}$做这题需要一个前置知识:多项式的多点求值
多项式的多点求值:给定多项式$f(x)$和$x_{1\cdots n}$,要求出$f(1)\cdots f(n)$
首先,我们可以找到$g_i(x)$使得$f(x)=(x-x_i)g_i(x)+C$(就是把$f(x)$对$x-x_i$取模),当$x=x_i$,我们得到$f(x_i)=C$,即$f(x_i)=\left.f(x)\%(x-x_i)\right|_{x=x_i}$,所以我们要求的是$f(x)\%(x-x_i)$,直接对$n$个$x_i$暴力求是$O(n^2\log_2n)$的,比暴力还慢,但一个很显然的事实是:如果$g(x)=h(x)r(x)$,那么$f(x)\%g(x)\%h(x)=f(x)\%h(x)$,所以我们这样分治求解:如果要求出$f(x)$在$x_{l\cdots r}$的取值,那么就递归计算$\align{f(x)\%\prod\limits_{i=l}^r(x-x_i)}$在$x_{l\cdots mid}$和$x_{mid+1\cdots r}$的取值,因为有取模,所以$f(x)$的次数被降了下来,总时间复杂度$T(n)=2T\left(\dfrac n2\right)+O(n\log_2n)=O(n\log_2^2n)$,注意要用分治FFT预处理出$\align{\prod\limits_{i=l}^r(x-x_i)}$,时间复杂度也是$O(n\log_2^2n)$,空间复杂度$O(n\log_2n)$
然后是这道题,因为是全局操作,所以我们定义$f_i(x)$表示经过$i$次操作后,原来的$x$会变成$f_i(x)$,每次操作要么是将$f(x)$加上一个常数,要么是把它取倒数,所以它的形式肯定是$f(x)=\dfrac{ax+b}{cx+d}=p+\dfrac q{x+t}$($c=0$要特殊处理)
所以我们要求的答案是$\align{\sum\limits_{i=1}^nf(x_i)}$,展开得到$\align{pn+q\sum\limits_{i=1}^n\dfrac1{x_i+t}}$,在这个式子中,$x_i$是常数,而$t$随着修改变化($m$个取值),所以我们把它看成关于$t$的函数$\align{g(t)=\sum\limits_{i=1}^n\dfrac1{x_i+t}}=\dfrac{\sum\limits_{i=1}^n\prod\limits_{j\ne i}(x_j+t)}{\prod\limits_{i=1}^n(x_i+t)}$,分母可以分治FFT算,分子是分母的导数,算出来后直接多点求值就做完了...
注意:凡是涉及分治FFT,需要new内存的,一定要注意不能访问超限,这时assert就派上用场了>_<
#include<stdio.h>
#include<string.h>
#include<assert.h>
const int mod=998244353,maxn=262144;
typedef long long ll;
int mul(int a,int b){return a*(ll)b%mod;}
int ad(int a,int b){return(a+b)%mod;}
int de(int a,int b){return(a-b)%mod;}
void swap(int&a,int&b){
int c=a;
a=b;
b=c;
}
int max(int a,int b){return a>b?a:b;}
int pow(int a,int b){
int s=1;
while(b){
if(b&1)s=mul(s,a);
a=mul(a,a);
b>>=1;
}
return s;
}
int rev[maxn],N,iN;
void pre(int n){
int i,k;
for(N=1,k=0;N<n;N<<=1)k++;
for(i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
iN=pow(N,mod-2);
}
void ntt(int*a,int on){
int i,j,k,t,w,wn;
for(i=0;i<N;i++){
if(i<rev[i])swap(a[i],a[rev[i]]);
}
for(i=2;i<=N;i<<=1){
wn=pow(3,(on==1)?(mod-1)/i:(mod-1-(mod-1)/i));
for(j=0;j<N;j+=i){
w=1;
for(k=0;k<i>>1;k++){
t=mul(w,a[i/2+j+k]);
a[i/2+j+k]=de(a[j+k],t);
a[j+k]=ad(a[j+k],t);
w=mul(w,wn);
}
}
}
if(on==-1){
for(i=0;i<N;i++)a[i]=mul(a[i],iN);
}
}
int t0[maxn];
void getinv(int*a,int*b,int n){
if(n==1){
b[0]=pow(a[0],mod-2);
return;
}
int i;
getinv(a,b,n>>1);
pre(n<<1);
memset(t0,0,N<<2);
memcpy(t0,a,n<<2);
ntt(t0,1);
ntt(b,1);
for(i=0;i<N;i++)b[i]=mul(b[i],2-mul(b[i],t0[i]));
ntt(b,-1);
for(i=n;i<N;i++)b[i]=0;
}
int ta[maxn],tb[maxn],tc[maxn];
void add(int*a,int n,int*b,int m,int*c,int&k){
k=max(n,m);
for(int i=0;i<=k;i++)tc[i]=ad(a[i],b[i]);
while(k!=0&&tc[k]==0)k--;
memcpy(c,tc,(k+1)<<2);
}
void dec(int*a,int n,int*b,int m,int*c,int&k){
k=max(n,m);
for(int i=0;i<=k;i++)tc[i]=de(a[i],b[i]);
while(k!=0&&tc[k]==0)k--;
memcpy(c,tc,(k+1)<<2);
}
void reverse(int*a,int n){
for(int i=0;i<=n>>1;i++)swap(a[i],a[n-i]);
}
void mul(int*a,int n,int*b,int m,int*c,int&k){
int i;
k=n+m;
pre(k+1);
memset(ta,0,N<<2);
memset(tb,0,N<<2);
memcpy(ta,a,(n+1)<<2);
memcpy(tb,b,(m+1)<<2);
ntt(ta,1);
ntt(tb,1);
for(i=0;i<N;i++)tc[i]=mul(ta[i],tb[i]);
ntt(tc,-1);
memcpy(c,tc,(k+1)<<2);
}
int t1[maxn];
void div(int*a,int n,int*b,int m,int*c,int&k){
if(n<m){
k=0;
return;
}
int i,rn;
for(rn=1;rn<n-m+1;rn<<=1);
memset(ta,0,rn<<3);
memset(tb,0,rn<<3);
memcpy(ta,a,(n+1)<<2);
memcpy(tb,b,(m+1)<<2);
reverse(tb,m);
for(i=rn;i<=m;i++)tb[i]=0;
memset(t1,0,rn<<3);
getinv(tb,t1,rn);
pre(rn<<1);
reverse(ta,n);
for(i=rn;i<=n;i++)ta[i]=0;
ntt(ta,1);
ntt(t1,1);
for(i=0;i<N;i++)tc[i]=mul(ta[i],t1[i]);
ntt(tc,-1);
k=n-m;
reverse(tc,k);
while(k!=0&&tc[k]==0)k--;
memcpy(c,tc,(k+1)<<2);
}
int len;
void modulo(int*a,int n,int*b,int m,int*c,int&k){
if(n<m){
k=n;
memcpy(c,a,(n+1)<<2);
return;
}
div(a,n,b,m,t1,k);
mul(t1,k,b,m,t1,k);
//assert(max(n,k)<=len);
dec(a,n,t1,k,c,k);
}
struct frac{//(ax+b)/(cx+d)
int a,b,c,d;
void add(int k){
a=ad(a,mul(c,k));
b=ad(b,mul(d,k));
}
void inv(){
swap(a,c);
swap(b,d);
}
}fr[60010];
int x[100010],op[60010],v[60010],ti[60010],*tr[240010],M;
void build(int l,int r,int x){
if(l==r){
tr[x]=new int[2];
tr[x][0]=-ti[l];
tr[x][1]=1;
return;
}
int mid=(l+r)>>1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
tr[x]=new int[r-l+2];
mul(tr[x<<1],mid-l+1,tr[x<<1|1],r-mid,tr[x],x);
}
void solve(int*f,int n,int l,int r,int x,int*ans){
int mid=(l+r)>>1,*now;
now=new int[r-l+1];
len=r-l;
modulo(f,n,tr[x],r-l+1,now,n);
if(l==r){
ans[l]=now[0];
return;
}
solve(now,n,l,mid,x<<1,ans);
solve(now,n,mid+1,r,x<<1|1,ans);
}
int t2[maxn],t3[maxn];
int*solve2(int l,int r){
int mid,*res,*L,*R,len;
res=new int[r-l+2];
if(l==r){
res[1]=1;
res[0]=x[l];
return res;
}
mid=(l+r)>>1;
L=solve2(l,mid);
R=solve2(mid+1,r);
mul(L,mid-l+1,R,r-mid,res,len);
return res;
}
int ans1[60010],ans2[60010],ans[60010],up[100010];
int main(){
int n,m,i,p,q,del,*res;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",x+i);
fr->a=fr->d=1;
fr->b=fr->c=0;
for(i=1;i<=m;i++){
fr[i]=fr[i-1];
scanf("%d",op+i);
if(op[i]==1){
scanf("%d",v+i);
fr[i].add(v[i]);
}else
fr[i].inv();
if(op[i]==2){
M++;
ti[M]=mul(fr[i].d,pow(fr[i].c,mod-2));
}
}
del=0;
for(i=1;i<=n;i++)ans[0]=ad(ans[0],x[i]);
if(M==0){
for(i=1;i<=m;i++){
del=ad(del,v[i]);
printf("%d\n",ad(ans[0],mul(del,n)));
}
return 0;
}
build(1,M,1);
res=solve2(1,n);
for(i=1;i<=n;i++)up[i-1]=mul(res[i],i);
solve(up,n-1,1,M,1,ans1);
solve(res,n,1,M,1,ans2);
M=del=0;
for(i=1;i<=m;i++){
if(op[i]==1){
del=ad(del,v[i]);
printf("%d\n",ad(ad(ans[M],mul(n,del)),mod));
}else{
M++;
if(fr[i].c==0){
printf("%d\n",ans[M]=ad(mul(ad(mul(fr[i].a,ans[0]),mul(fr[i].b,n)),pow(fr[i].d,mod-2)),mod));
continue;
}
p=mul(fr[i].a,pow(fr[i].c,mod-2));
q=mul(de(mul(fr[i].b,fr[i].c),mul(fr[i].a,fr[i].d)),pow(mul(fr[i].c,fr[i].c),mod-2));
ans[M]=ad(mul(p,n),mul(q,mul(ans1[M],pow(ans2[M],mod-2))));
printf("%d\n",ad(ans[M],mod));
del=0;
}
}
}
[UOJ182]a^-1 + b problem的更多相关文章
- UOJ182 a^-1 + b problem 解题报告
题目描述 有一个长度为\(n(n\le 10^5)\)的数列,在模\(M\)意义下进行\(m(m \le50000)\)次操作,每次操作形如以下两种形式: 1 \(x\) 表示每个数加\(x(0 \l ...
- GOOD BYE OI
大米饼正式退役了,OI给我带来很多东西 我会的数学知识基本都在下面了 博客园的评论区问题如果我看到了应该是会尽力回答的... 这也是我作为一个OIer最后一次讲课的讲稿 20190731 多项式乘法 ...
- 1199 Problem B: 大小关系
求有限集传递闭包的 Floyd Warshall 算法(矩阵实现) 其实就三重循环.zzuoj 1199 题 链接 http://acm.zzu.edu.cn:8000/problem.php?id= ...
- No-args constructor for class X does not exist. Register an InstanceCreator with Gson for this type to fix this problem.
Gson解析JSON字符串时出现了下面的错误: No-args constructor for class X does not exist. Register an InstanceCreator ...
- C - NP-Hard Problem(二分图判定-染色法)
C - NP-Hard Problem Crawling in process... Crawling failed Time Limit:2000MS Memory Limit:262144 ...
- Time Consume Problem
I joined the NodeJS online Course three weeks ago, but now I'm late about 2 weeks. I pay the codesch ...
- Programming Contest Problem Types
Programming Contest Problem Types Hal Burch conducted an analysis over spring break of 1999 and ...
- hdu1032 Train Problem II (卡特兰数)
题意: 给你一个数n,表示有n辆火车,编号从1到n,入站,问你有多少种出站的可能. (题于文末) 知识点: ps:百度百科的卡特兰数讲的不错,注意看其参考的博客. 卡特兰数(Catalan):前 ...
- BZOJ2301: [HAOI2011]Problem b[莫比乌斯反演 容斥原理]【学习笔记】
2301: [HAOI2011]Problem b Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 4032 Solved: 1817[Submit] ...
随机推荐
- 2017年研究生数学建模D题(前景目标检测)相关论文与实验结果
一直都想参加下数学建模,通过几个月培训学到一些好的数学思想和方法,今年终于有时间有机会有队友一起参加了研究生数模,but,为啥今年说不培训直接参加国赛,泪目~_~~,然后比赛前也基本没看,直接硬刚.比 ...
- 使用 FirewallD 构建动态防火墙
使用 FirewallD 构建动态防火墙 FirewallD 提供了支持网络/防火墙区域(zone)定义网络链接以及接口安全等级的动态防火墙管理工具.它支持 IPv4, IPv6 防火墙设置以及以太网 ...
- Kafka自我学习-报错篇
1. kafka启动出现:Unsupported major.minor version 52.0 错误, 具体的错误输出: Exception in thread "main" ...
- 调整文本输入框placeholder的颜色等样式
input::-webkit-input-placeholder{ color: white !important;}input:-moz-placeholder{ color: whi ...
- 如何去掉Json字符串中反斜杠
做项目的时候,遇到了这样的问题,前台传来的Json字符串在实体类中不对应(无法转换为实体类),而且传来的数据项是跟着数据库中的表的变动而变动的(不能重写实体类). 前台Json字符串为: string ...
- JAVA路线
[转]Java自学之路——by马士兵 作者:马士兵老师 JAVA自学之路 一:学会选择 为了就业,不少同学参加各种各样的培训. 决心做软件的,大多数人选的是java,或是.net,也有一些选择了手机. ...
- bzoj1861 书架 splay版
单点插入删除以及求前缀 #include<cstdio> #include<cstring> #include<algorithm> using namespace ...
- [BZOJ1036][ZJOI2008]树的统计Count 解题报告|树链剖分
树链剖分 简单来说就是数据结构在树上的应用.常用的为线段树splay等.(可现在splay还不会敲囧) 重链剖分: 将树上的边分成轻链和重链. 重边为每个节点到它子树最大的儿子的边,其余为轻边. 设( ...
- [BZOJ3261&BZOJ3166]可持久化trie树及其应用
可持久化trie树 可持久化trie树现在想来是比较好理解的了,但却看了一个下午... 相当于对于每个状态建立一条链(或者说一棵trie),求解的时候只要让两个点按照相同的步子走然后看sum的大小关系 ...
- 【反演复习计划】【bzoj2818】gcd
就是之前的2820的升级版. 把暴力枚举素数改成预处理就随便A了. #include<bits/stdc++.h> #define N 10000005 #define ll long l ...