luoguP5219 无聊的水题 I 多项式快速幂
有一个幼儿园容斥:最大次数恰好为 $m=$ 最大次数最多为 $m$ - 最大次数最多为 $m-1$.
然后来一个多项式快速幂就好了.
code:
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <string>
#define ll long long
#define ull unsigned long long
using namespace std;
namespace IO
{
char buf[100000],*p1,*p2;
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd()
{
int x=0; char s=nc();
while(s<'0') s=nc();
while(s>='0') x=(((x<<2)+x)<<1)+s-'0',s=nc();
return x;
}
void print(int x) {if(x>=10) print(x/10);putchar(x%10+'0');}
void setIO(string s)
{
string in=s+".in";
string out=s+".out";
freopen(in.c_str(),"r",stdin);
// freopen(out.c_str(),"w",stdout);
}
};
const int G=3;
const int N=400005;
const int mod=998244353;
int A[N],B[N],w[2][N],mem[N*100],*ptr=mem,tmpa[N],tmpb[N],aa[N],bb[N];
inline int qpow(int x,int y)
{
int tmp=1;
for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) tmp=(ll)tmp*x%mod;
return tmp;
}
inline int INV(int a) { return qpow(a,mod-2); }
inline void ntt_init(int len)
{
int i,j,k,mid,x,y;
w[1][0]=w[0][0]=1,x=qpow(G,(mod-1)/len),y=qpow(x,mod-2);
for (i=1;i<len;++i) w[0][i]=(ll)w[0][i-1]*x%mod,w[1][i]=(ll)w[1][i-1]*y%mod;
}
void NTT(int *a,int len,int flag)
{
int i,j,k,mid,x,y;
for(i=k=0;i<len;++i)
{
if(i>k) swap(a[i],a[k]);
for(j=len>>1;(k^=j)<j;j>>=1);
}
for(mid=1;mid<len;mid<<=1)
for(i=0;i<len;i+=mid<<1)
for(j=0;j<mid;++j)
{
x=a[i+j], y=(ll)w[flag==-1][len/(mid<<1)*j]*a[i+j+mid]%mod;
a[i+j]=(x+y)%mod;
a[i+j+mid]=(x-y+mod)%mod;
}
if(flag==-1)
{
int rev=INV(len);
for(i=0;i<len;++i) a[i]=(ll)a[i]*rev%mod;
}
}
inline void getinv(int *a,int *b,int len,int la)
{
if(len==1) { b[0]=INV(a[0]); return; }
getinv(a,b,len>>1,la);
int l=len<<1,i;
memset(A,0,l*sizeof(A[0]));
memset(B,0,l*sizeof(A[0]));
memcpy(A,a,min(la,len)*sizeof(a[0]));
memcpy(B,b,len*sizeof(b[0]));
ntt_init(l);
NTT(A,l,1),NTT(B,l,1);
for(i=0;i<l;++i) A[i]=((ll)2-(ll)A[i]*B[i]%mod+mod)*B[i]%mod;
NTT(A,l,-1);
memcpy(b,A,len<<2);
}
void get_dao(int *a,int *b,int len)
{
for(int i=1;i<len;++i) b[i-1]=(ll)i*a[i]%mod;
b[len-1]=0;
}
void get_jifen(int *a,int *b,int len)
{
for(int i=1;i<len;++i) b[i]=(ll)INV(i)*a[i-1]%mod;
b[0]=0;
}
void get_ln(int *a,int *b,int len,int la)
{
int l=len<<1,i;
memset(tmpa,0,l<<2);
memset(tmpb,0,l<<2);
get_dao(a,tmpa,min(len,la));
getinv(a,tmpb,len,la);
ntt_init(l);
NTT(tmpa,l,1),NTT(tmpb,l,1);
for(i=0;i<l;++i) tmpa[i]=(ll)tmpa[i]*tmpb[i]%mod;
NTT(tmpa,l,-1);
get_jifen(tmpa,b,len);
}
void get_exp(int *a,int *b,int len,int la)
{
if(len==1) { b[0]=1; return; }
int l=len<<1,i;
get_exp(a,b,len>>1,la);
for(i=0;i<l;++i) aa[i]=bb[i]=0;
for(i=0;i<(len>>1);++i) aa[i]=b[i];
get_ln(b,bb,len,len>>1);
for(i=0;i<len;++i) bb[i]=(ll)(mod-bb[i]+(i>=la?0:a[i]))%mod;
bb[0]=(bb[0]+1)%mod;
ntt_init(l);
NTT(aa,l,1),NTT(bb,l,1);
for(i=0;i<l;++i) aa[i]=(ll)aa[i]*bb[i]%mod;
NTT(aa,l,-1);
for(i=0;i<len;++i) b[i]=aa[i];
}
struct poly
{
int len,*a;
poly(){}
poly(int l) {len=l,a=ptr,ptr+=l; }
inline void rev() { reverse(a,a+len); }
inline void fix(int l) {len=l,a=ptr,ptr+=l;}
inline void get_mod(int l) { for(int i=l;i<len;++i) a[i]=0; len=l; }
inline poly dao()
{
poly re(len-1);
for(int i=1;i<len;++i) re.a[i-1]=(ll)i*a[i]%mod;
return re;
}
inline poly jifen()
{
poly c;
c.fix(len+1);
c.a[0]=0;
for(int i=1;i<=len;++i) c.a[i]=(ll)a[i-1]*INV(i)%mod;
return c;
}
inline poly Inv(int l)
{
int lim=1;
while(lim<=l) lim<<=1;
poly b(lim);
getinv(a,b.a,lim,len);
b.get_mod(l);
return b;
}
inline poly ln(int l)
{
int lim=1;
while(lim<=l) lim<<=1;
poly b(lim);
get_ln(a,b.a,lim,len);
return b;
}
inline poly exp(int l)
{
int lim=1;
while(lim<=l) lim<<=1;
poly b(lim);
get_exp(a,b.a,lim,len);
return b;
}
inline poly q_pow(int k,int l)
{
int lim=1;
while(lim<=l) lim<<=1;
poly b(lim),c(lim);
get_ln(a,b.a,lim,len);
for(int i=0;i<b.len;++i) b.a[i]=(ll)b.a[i]*k%mod;
get_exp(b.a,c.a,lim,b.len);
c.get_mod(l);
return c;
}
inline poly operator*(const poly &b) const
{
poly c(len+b.len-1);
if(c.len<=500)
{
for(int i=0;i<len;++i)
if(a[i]) for(int j=0;j<b.len;++j) c.a[i+j]=(c.a[i+j]+(ll)(a[i])*b.a[j])%mod;
return c;
}
int n=1;
while(n<(len+b.len)) n<<=1;
memset(A,0,n<<2);
memset(B,0,n<<2);
memcpy(A,a,len<<2);
memcpy(B,b.a,b.len<<2);
ntt_init(n);
NTT(A,n,1), NTT(B,n,1);
for(int i=0;i<n;++i) A[i]=(ll)A[i]*B[i]%mod;
NTT(A,n,-1);
memcpy(c.a,A,c.len<<2);
return c;
}
poly operator+(const poly &b) const
{
poly c(max(len,b.len));
for(int i=0;i<c.len;++i) c.a[i]=((i<len?a[i]:0)+(i<b.len?b.a[i]:0))%mod;
return c;
}
poly operator-(const poly &b) const
{
poly c(len);
for(int i=0;i<len;++i)
{
if(i>=b.len) c.a[i]=a[i];
else c.a[i]=(a[i]-b.a[i]+mod)%mod;
}
return c;
}
poly operator/(poly u)
{
int n=len,m=u.len,l=1;
while(l<(n-m+1)) l<<=1;
rev(),u.rev();
poly v=u.Inv(l);
v.get_mod(n-m+1);
poly re=(*this)*v;
rev(),u.rev();
re.get_mod(n-m+1);
re.rev();
return re;
}
poly operator%(poly u)
{
poly re=(*this)-u*(*this/u);
re.get_mod(u.len-1);
return re;
}
};
#define MAX 200005
int fac[N],inv[N],n,m;
void init()
{
fac[0]=inv[0]=1;
int i,j;
for(i=1;i<MAX;++i) fac[i]=(ll)fac[i-1]*i%mod,inv[i]=INV(fac[i]);
}
// 最大出现次数为 k
int calc(int k)
{
poly g(n);
int i,j;
for(i=0;i<=k;++i) g.a[i]=inv[i];
g=g.q_pow(n,n);
return (ll)fac[n-2]*g.a[n-2]%mod;
}
int main()
{
// IO::setIO("input");
init();
int i,j;
scanf("%d%d",&n,&m);
printf("%d\n",(ll)(calc(m-1)-calc(m-2)+mod)%mod);
return 0;
}
luoguP5219 无聊的水题 I 多项式快速幂的更多相关文章
- 洛谷P5219 无聊的水题 I [prufer序列,生成函数,NTT]
传送门 思路 有标号无根树的计数,还和度数有关,显然可以想到prufer序列. 问题就等价于求长度为\(n-2\),值域为\([1,n]\),出现次数最多的恰好出现\(m-1\)次,这样的序列有哪些. ...
- 【xsy2479】counting 生成函数+多项式快速幂
题目大意:在字符集大小为$m$的情况下,有多少种构造长度为$n$的字符串$s$的方案,使得$C(s)=k$.其中$C(s)$表示字符串$s$中出现次数最多的字符的出现次数. 对$998244353$取 ...
- 【bzoj3684】 大朋友和多叉树 生成函数+多项式快速幂+拉格朗日反演
这题一看就觉得是生成函数的题... 我们不妨去推下此题的生成函数,设生成函数为$F(x)$,则$[x^s]F(x)$即为答案. 根据题意,我们得到 $F(x)=x+\sum_{i∈D} F^i(x)$ ...
- BZOJ3645: Maze(FFT多项式快速幂)
Description 众维拉先后在中土大陆上创造了精灵.人类以及矮人,其中矮人是生性喜好常年居住在地下的洞穴的存在,他们挖掘矿物甚至宝石,甚至用他们的勤劳勇敢智慧在地底下创造出了辉煌宏大的宫殿,错综 ...
- AtCoder AGC019E Shuffle and Swap (DP、FFT、多项式求逆、多项式快速幂)
题目链接 https://atcoder.jp/contests/agc019/tasks/agc019_e 题解 tourist的神仙E题啊做不来做不来--这题我好像想歪了啊= =-- 首先我们可以 ...
- [SDOI2015]序列统计(多项式快速幂)
题目描述 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S.小C用这个生成器生成了许多这样的数列.但是小C有一个问 ...
- 【BZOJ3992】[SDOI2015]序列统计 NTT+多项式快速幂
[BZOJ3992][SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属 ...
- (中等) CF 576D Flights for Regular Customers (#319 Div1 D题),矩阵快速幂。
In the country there are exactly n cities numbered with positive integers from 1 to n. In each city ...
- E题:Water Problem(快速幂模板)
题目大意:原题链接 题解链接 解题思路:令x=x-1代入原等式得到新的等式,两式相加,将sin()部分抵消掉,得到只含有f(x)的状态转移方程f(x+1)=f(x)+f(x-2)+f(x-3),然后 ...
随机推荐
- java设计模式7——桥接模式
java设计模式7--桥接模式 1.桥接模式介绍 桥接模式是将抽象部分与它的实现部分分离,使他们都可以独立的变化.它是一种对象结构型模式,又称为柄体模式或接口模式. 2.解决问题 2.1.将复杂的组合 ...
- Go语言实现:【剑指offer】删除链表中重复的结点
该题目来源于牛客网<剑指offer>专题. 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中没有重复出现的数字. 示例 1: 输入: 1->2->3->3- ...
- 【译文连载】 理解Istio服务网格(第三章 流控)
第3章 流控.............................................................................................. ...
- apache主配置文件httpd.conf详解
[root@lamp conf]# vi httpd.conf.bak 1 # 2 # This is the main Apache HTTP server configuration file. ...
- Vue.js 计算属性computed和methods的区别
在vue.js中,有methods和computed两种方式来动态当作方法来用的 如下: 两种方式在这种情况下的结果是一样的 写法上的区别是computed计算属性的方式在用属性时不用加(),而met ...
- 剖析Java OutOfMemoryError异常
剖析Java OutOfMemoryError异常 在JVM中,除了程序计数器外,虚拟机内存中的其他几个运行时区域都有发生OutOfMemoryError异常的可能,本篇就来深入剖析一下各个区域出现O ...
- C#设计模式学习笔记:(23)解释器模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8242238.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第十一个模式-- ...
- 显示层封装及实现与优化(无动画+css3动画+js动画)
showhide.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...
- 【mysql】索引相关的个人总结
重点参考: MySQL索引原理及慢查询优化 (美团技术分享网站):原理.示例优化都写的很好. 索引很难么?带你从头到尾捋一遍MySQL索引结构,不信你学不会!:原理写的很好. [从入门到入土]令人脱发 ...
- 反射机制(reflection)
一.反射: 1.反射指可以在运行时加载.探知.使用编译期间完全未知的类. 2.程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已加载的类,都能够知道这个类的所有属性和方法: 对于任意一个对 ...