洛谷P4705 玩游戏 [生成函数,NTT]
这是两个月之前写的题,但没写博客。现在回过头来看一下发现又不会了……
还是要写博客加深记忆。
思路
显然期望可以算出总数再乘上\((nm)^{-1}\)。
那么有
ans_t&=\sum_{i=1}^n \sum_{j=1}^m (a_i+b_j)^t\\
&=\sum_{i=1}^n \sum_{j=1}^m \sum_{k=0}^t {t\choose k} a_i^k b_j^{t-k}\\
&=t!\sum_{k=0}^t (\sum_{i=1}^n \frac{a_i^k}{k!}) (\sum_{j=1}^m \frac{b_j^{t-k}}{(t-k)!})\\
\end {align*}
\]
显然是个卷积的形式,但怎么求\(\sum a_i^k\)呢?
这似乎是个套路。
设多项式
\]
那么所求即为
\]
考虑一个式子:
[\sum_{i=1}^n \ln(1-a_ix)]'&=\sum_{i=1}^n [\ln(1-a_ix)]'\\
&=\sum_{i=1}^n \frac{a_i}{1-a_ix}\\
&=\sum_{i=1}^n \sum_{j} a_i^{j+1}x^j\\
&=\frac{1}{x}\sum_{i=1}^n \sum_{j=1}^{\infty} a_i^jx^j\\
&=\frac 1 x \sum_{i=1}^n [f_i(x)-1]
\end{align*}
\]
好像非常好,但这东西怎么求呢?
设
\]
则有
\]
显然\(g(x)\)可以分治NTT求得,然后就可以求得\(\sum f_i\),然后再NTT一下就可以得到答案了。
代码
#include<bits/stdc++.h>
namespace my_std{
    using namespace std;
    #define rep(i,x,y) for (register int i=(x);i<=(y);++i)
    #define drep(i,x,y) for (register int i=(x);i>=(y);--i)
    #define mod 998244353ll
    #define sz 401010
    typedef long long ll;
    template<typename T>
    inline void read(T& t)
    {
        t=0;char f=0,ch=getchar();
        double d=0.1;
        while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
        while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
        if(ch=='.')
        {
            ch=getchar();
            while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();
        }
        t=(f?-t:t);
    }
    template<typename T,typename... Args>
    inline void read(T& t,Args&... args){read(t); read(args...);}
    void file()
    {
        #ifndef ONLINE_JUDGE
        freopen("a.txt","r",stdin);
        #endif
    }
//	inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
ll ksm(ll x,int y)
{
    ll ret=1;
    for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;
    return ret;
}
#define inv(x) ksm(x,mod-2)
int r[sz],limit;
void NTT_init(int n)
{
    limit=1;int l=-1;
    while (limit<=n+n) limit<<=1,++l;
    rep(i,0,limit-1) r[i]=(r[i>>1]>>1)|((i&1)<<l);
}
void NTT(ll *a,int type)
{
    rep(i,0,limit-1) if (r[i]<i) swap(a[i],a[r[i]]);
    for (int mid=1;mid<limit;mid<<=1)
    {
        ll Wn=ksm(3,(mod-1)/mid>>1);if (type==-1) Wn=inv(Wn);
        for (int len=mid<<1,j=0;j<limit;j+=len)
        {
            ll w=1;
            for (int k=0;k<mid;k++,w=w*Wn%mod)
            {
                ll x=a[j+k],y=a[j+k+mid]*w;
                a[j+k]=(x+y)%mod;a[j+k+mid]=(mod*mod+x-y)%mod;
            }
        }
    }
    if (type==1) return;
    ll I=inv(limit);
    rep(i,0,limit-1) a[i]=a[i]*I%mod;
}
namespace GetLn
{
    ll g[sz];
    ll inv[sz];
    ll a[sz],b[sz];
    void work_inv(int n)// inv=g^{-1} (mod x^n)
    {
        if (n==1) return (void)(inv[0]=::inv(g[0]));
        int mid=(n+1)>>1;
        work_inv(mid);
        NTT_init(n);
        rep(i,0,mid-1) a[i]=inv[i];rep(i,mid,limit-1) a[i]=0;
        rep(i,0,n-1) b[i]=g[i];rep(i,n,limit-1) b[i]=0;
        NTT(a,1);NTT(b,1);
        rep(i,0,limit-1) a[i]=a[i]*(mod+2-a[i]*b[i]%mod)%mod;
        NTT(a,-1);
        rep(i,0,n-1) inv[i]=a[i];
    }
    void work1(ll *a,int n){rep(i,0,n-2) a[i]=a[i+1]*(i+1)%mod;a[n-1]=0;}
    void work2(ll *a,int n){drep(i,n,1) a[i]=a[i-1]*::inv(i)%mod;a[0]=0;}
    void Ln(ll *F,int n)// F=ln F (mod x^{n+1})
    {
        memset(g,0,sizeof(g));memset(inv,0,sizeof(inv));
        rep(i,0,n) g[i]=F[i];
        work_inv(n+1);
        work1(g,n);
        NTT_init(n);
        NTT(inv,1);NTT(g,1);
        rep(i,0,limit-1) F[i]=inv[i]*g[i]%mod;
        NTT(F,-1);
        work2(F,n);
        rep(i,n,limit-1) F[i]=0;
    }
}
int S[55],top;// tmp available
ll tmp[55][sz];
void solve(int l,int r,ll *ret,int *a)
{
    if (l==r) return (void)(ret[0]=1,ret[1]=a[l]);
    int mid=(l+r)>>1;
    int ls=S[top--];solve(l,mid,tmp[ls],a);
    int rs=S[top--];solve(mid+1,r,tmp[rs],a);
    NTT_init(r-l+1);
    NTT(tmp[ls],1);NTT(tmp[rs],1);
    rep(i,0,limit-1) ret[i]=tmp[ls][i]*tmp[rs][i]%mod;
    NTT(ret,-1);
    S[++top]=ls;S[++top]=rs;
    rep(i,0,limit-1) tmp[ls][i]=tmp[rs][i]=0;
}
int n,m,T;
ll A[sz],B[sz];
int a[sz>>2],b[sz>>2];
ll fac[sz>>2],_fac[sz>>2];
void init(int n)
{
    fac[0]=_fac[0]=1;
    rep(i,1,n) fac[i]=fac[i-1]*i%mod;
    _fac[n]=inv(fac[n]);
    drep(i,n-1,1) _fac[i]=_fac[i+1]*(i+1)%mod;
}
int main()
{
    file();
    read(n,m);
    rep(i,1,n) read(a[i]);
    rep(i,1,m) read(b[i]);
    read(T);
    init(T);
    rep(i,0,50) S[i]=i;top=50;solve(1,n,A,a);
    GetLn::Ln(A,T+1);
    rep(i,0,50) S[i]=i;top=50;solve(1,m,B,b);
    GetLn::Ln(B,T+1);
    rep(i,1,T) A[i]=A[i]*i%mod,A[i]=(i&1)?A[i]:mod-A[i];
    rep(i,1,T) B[i]=B[i]*i%mod,B[i]=(i&1)?B[i]:mod-B[i];
    A[0]=n;B[0]=m;
    rep(i,0,T) A[i]=_fac[i]*A[i]%mod;
    rep(i,0,T) B[i]=_fac[i]*B[i]%mod;
    NTT_init(T);
    NTT(A,1);NTT(B,1);
    rep(i,0,limit-1) A[i]=A[i]*B[i]%mod;
    NTT(A,-1);
    rep(i,0,T) A[i]=A[i]*fac[i]%mod;
    ll I=inv(1ll*n*m%mod);
    rep(i,1,T) printf("%lld\n",A[i]*I%mod);
}
												
											洛谷P4705 玩游戏 [生成函数,NTT]的更多相关文章
- 洛谷 P4705 玩游戏 解题报告
		
P4705 玩游戏 题意:给长为\(n\)的\(\{a_i\}\)和长为\(m\)的\(\{b_i\}\),设 \[ f(x)=\sum_{k\ge 0}\sum_{i=1}^n\sum_{j=1}^ ...
 - 洛谷P4705 玩游戏(生成函数+多项式运算)
		
题面 传送门 题解 妈呀这辣鸡题目调了我整整三天--最后发现竟然是因为分治\(NTT\)之后的多项式长度不是\(2\)的幂导致把多项式的值存下来的时候发生了一些玄学错误--玄学到了我\(WA\)的点全 ...
 - [洛谷P4705]玩游戏
		
题目大意:对于每个$k\in[1,t]$,求:$$\dfrac{\sum\limits_{i=1}^n\sum\limits_{j=1}^m(a_i+b_j)^k}{nm}$$$n,m,t\leqsl ...
 - 洛谷 P4705 玩游戏
		
题目分析 题目要求的是: \[ \sum_{i=1}^n\sum_{j=1}^m(a_i+b_j)^x(x\in [1,T]) \] 利用二项式定理化式子, \[ \begin{aligned} &a ...
 - 【洛谷5月月赛】玩游戏(NTT,生成函数)
		
[洛谷5月月赛]玩游戏(NTT,生成函数) 题面 Luogu 题解 看一下要求的是什么东西 \((a_x+b_y)^i\)的期望.期望显然是所有答案和的平均数. 所以求出所有的答案就在乘一个逆元就好了 ...
 - 洛谷 P2197 nim游戏
		
洛谷 P2197 nim游戏 题目描述 甲,乙两个人玩Nim取石子游戏. nim游戏的规则是这样的:地上有n堆石子(每堆石子数量小于10000),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取 ...
 - 洛谷 P1965 转圈游戏
		
洛谷 P1965 转圈游戏 传送门 思路 每一轮第 0 号位置上的小伙伴顺时针走到第 m 号位置,第 1 号位置小伙伴走到第 m+1 号位置,--,依此类推,第n − m号位置上的小伙伴走到第 0 号 ...
 - Luogu P4705 玩游戏
		
题目描述 Alice 和 Bob 又在玩游戏. 对于一次游戏,首先 Alice 获得一个长度为  的序列 ,Bob 获得一个长度为  的序列 bb.之后他们各从自己的序列里随机取出一个数,分别设 ...
 - 【流水调度问题】【邻项交换对比】【Johnson法则】洛谷P1080国王游戏/P1248加工生产调度/P2123皇后游戏/P1541爬山
		
前提说明,因为我比较菜,关于理论性的证明大部分是搬来其他大佬的,相应地方有注明. 我自己写的部分换颜色来便于区分. 邻项交换对比是求一定条件下的最优排序的思想(个人理解).这部分最近做了一些题,就一起 ...
 
随机推荐
- CC2541设置中断输入模式
			
//P0.0 /* SW_6 is at P0.1 */#define HAL_KEY_SW_6_PORT P0#define HAL_KEY_SW_6_BIT BV(0)#define HAL_KE ...
 - VS中ipch文件夹和sdf文件的处理方式
			
ipch文件夹和sdf是VS产生的预编译头文件和智能提示信息,对编码没有影响,可存放在固定的位置,定期进行清理
 - plsql 根据sid连接oracle
			
ORCL73 = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.73)(PORT = 152 ...
 - [C++]Linux之头文件sys/types.h[/usr/include/sys]
			
1.查找<sys/types.h>文件 一般地,Linux的C头文件<sys/types.h>路径在如题的途径:/usr/include/sys下,然而博主[Linux For ...
 - linux下mysql 配置
			
su root 加环境变量 在文件末尾加上如下两行代码 PATH=/usr/local/webserver/php/bin:$PATHexport PATH # /etc/profile 保存,重启 ...
 - RSA加解密-2
			
Java使用RSA加密解密签名及校验 package com.ihep; import java.io.BufferedReader; import java.io.BufferedWriter; ...
 - Centos7 nginx提示错误 Access denied.
			
SELinux will cause this error on CentOS/RHEL 7+ by default :( CentOS/RHEL 7+ 系统默认会因为SELinux出现这个报错 To ...
 - RabbitMQ简单应用の公平分发(fair dipatch)
			
公平分发(fair dipatch)和轮询分发其实基本一致,只是每次分发的机制变了,由原来的平均分配到现在每次只处理一条消息 1.MQ连接工厂类Connection package com.mmr.r ...
 - Linux安装JDK(tar)
			
我以JDK1.8为例 ⒈下载 https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html ...
 - linux+php实现定时任务[链接]
			
1.crontab 详细用法 定时任务 https://www.cnblogs.com/aminxu/p/5993769.html 2.查看crontab日志 https://www.cnblogs. ...