题目描述

  小南一共有\(n\)种不同的玩具小人,每种玩具小人的数量都可以被认为是无限大。每种玩具小人都有特定的血量,第\(i\)种玩具小人的血量就是整数\(i\)。此外,每种玩具小人还有自己的攻击力,攻击力可以是任意非负整数,且两种不同的玩具小人的攻击力可以相同。我们把第\(i\)种玩具小人的血量和攻击力表示成\(a_i\)和\(b_i\)。

  为了让玩具小人们进行战斗,小南打算把一些小人选出来,编成队伍。一个队伍可以表示成一个由玩具小人组成的序列:\((p_1,p_2,\ldots,p_l)\),其中\(p_i\)表示队伍中第\(i\)个玩具小人的种类,\(l\)为队伍的长度。对于不同的\(i\),\(p_i\)可以相同。两个队伍被认为相同,当且仅当长度相同,且每个位置的玩具小人种类都分别相同。

  一个队伍也有血量和攻击力两个属性,记为\(a_t,b_t\)。队伍的血量就是每个玩具小人的血量之和,而队伍攻击力可能会由于队伍内部产生矛盾而减小,对于长度为\(l\)的队伍,队伍的攻击力为每个玩具小人的攻击力之乘积除以\(l\)的阶乘。同时,当\(l\)大于等于某个常数\(c\)时,攻击力会有一个额外的加成:乘以\((1+\frac{l!}{(l−c)!})\)。也就是说:

\[a_t=\sum_{i=1}^la_{p_i}\\
b_t=\begin{cases}
\frac{1}{l!}\sum_{i=1}^lb_{p_i}&,l<c\\
(\frac{1}{l!}+\frac{1}{(l-c)!})\sum_{i=1}^lb_{p_i}&,l\geq c
\end{cases}
\]

  然而,小南的玩具小人们对小南的独裁统治感到愤怒,准备联合起来发起民主运动。为了旗帜鲜明地反对动乱,小南必须了解清楚玩具小人们的战斗力。不幸的是,由于玩具小人数量过多,小南已经忘记每种玩具小人的战斗力具体是多少了。现在,小南掌握的情报只有对于每个\(1\)和\(n\)之间的整数\(i\),所有血量等于\(i\)的不同队伍的战斗力之和对\(998244353\)取模的值是多少(\(s_i\))。他希望你根据已有的情报,还原出每种玩具小人的战斗力对\(998244353\)取模的结果 。如果镇压成功了,小南会请你到北京去做一回总书记(当然是北京玩具协会的总书记)。

  \(n\leq 60000,0\leq c\leq n\)

题解

  设\(F=\sum_{i\geq 1}b_i,S=\sum_{i\geq 0}s_i\),如果\(c=0\),那么\(s_0=2\)

\[\begin{align}
\sum_{i\geq 0}\frac{F^i}{i!}+\sum_{i\geq 0}\frac{F^i}{i!}&=S\\
2e^F&=S\\
F=\ln\frac{S}{2}
\end{align}
\]

  否则\(s_0=1\)

\[\begin{align}
\sum_{i\geq 1}\frac{F^i}{i!}+\sum_{i\geq c}\frac{F^i}{(i-c)!}&=S-1\\
\sum_{i\geq 1}\frac{F^i}{i!}+F^c\sum_{i\geq0}\frac{F^i}{i!}&=S-1\\
(F^c+1)e^F&=S
\end{align}
\]

  然后就是牛顿迭代解方程。我们需要满足

\[g(F)=(F^c+1)e^F-S=0
\]

  的\(F\)。设当前求出了

\[g(F_0)\equiv0\pmod {x^{\frac{n}{2}}}
\]

  的\(F_0\),现在我们要求\(F\)满足

\[g(F)\equiv 0\pmod {x^n}
\]

  考虑在\(F_0\)出对\(g\)泰勒展开

\[g(F)=g(F_0)+g'(F_0)(F-F_0)+\frac{g''(F_0)}{2}{(F-F_0)}^2+\cdots
\]

  后面的项都是\(0\),因为\(F-F_0\)的最小非零项的次数至少是\(\frac{n}{2}\),所以后面的部分在模\(x^n\)意义下一定会被消掉。

  式子就变成了

\[\begin{align}
g(F)&\equiv g(F_0)+g'(F_0)(F-F_0)\pmod {x^n}\\
F&\equiv F_0-\frac{g(F_0)}{g'(F_0)}\pmod {x^n}\\
F&\equiv F_0-\frac{({F_0}^c+1)e^{F_0}-S}{(c{F_0}^{c-1}+{F_0}^c+1)e^{F_0}}\pmod {x^n}
\end{align}
\]

  套各种多项式算法可以做到

\[T(n)=T(\frac{n}{2})+O(n\log n)=O(n\log n)
\]

  常数巨大。

代码

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<cstdlib>
  5. #include<ctime>
  6. #include<utility>
  7. #include<cmath>
  8. #include<functional>
  9. using namespace std;
  10. typedef long long ll;
  11. typedef unsigned long long ull;
  12. typedef pair<int,int> pii;
  13. typedef pair<ll,ll> pll;
  14. void sort(int &a,int &b)
  15. {
  16. if(a>b)
  17. swap(a,b);
  18. }
  19. void open(const char *s)
  20. {
  21. #ifndef ONLINE_JUDGE
  22. char str[100];
  23. sprintf(str,"%s.in",s);
  24. freopen(str,"r",stdin);
  25. sprintf(str,"%s.out",s);
  26. freopen(str,"w",stdout);
  27. #endif
  28. }
  29. int rd()
  30. {
  31. int s=0,c;
  32. while((c=getchar())<'0'||c>'9');
  33. do
  34. {
  35. s=s*10+c-'0';
  36. }
  37. while((c=getchar())>='0'&&c<='9');
  38. return s;
  39. }
  40. void put(int x)
  41. {
  42. if(!x)
  43. {
  44. putchar('0');
  45. return;
  46. }
  47. static int c[20];
  48. int t=0;
  49. while(x)
  50. {
  51. c[++t]=x%10;
  52. x/=10;
  53. }
  54. while(t)
  55. putchar(c[t--]+'0');
  56. }
  57. int upmin(int &a,int b)
  58. {
  59. if(b<a)
  60. {
  61. a=b;
  62. return 1;
  63. }
  64. return 0;
  65. }
  66. int upmax(int &a,int b)
  67. {
  68. if(b>a)
  69. {
  70. a=b;
  71. return 1;
  72. }
  73. return 0;
  74. }
  75. const ll p=998244353;
  76. const ll g=3;
  77. const int maxn=65536;
  78. ll fp(ll a,ll b)
  79. {
  80. ll s=1;
  81. for(;b;b>>=1,a=a*a%p)
  82. if(b&1)
  83. s=s*a%p;
  84. return s;
  85. }
  86. ll inv[200000];
  87. namespace ntt
  88. {
  89. int rev[200000];
  90. int m;
  91. void ntt(ll *a,int n,int t)
  92. {
  93. ll u,v,w,wn;
  94. int i,j,k;
  95. if(n!=m)
  96. {
  97. m=n;
  98. rev[0]=0;
  99. for(i=1;i<n;i++)
  100. rev[i]=(rev[i>>1]>>1)|(i&1?n>>1:0);
  101. }
  102. for(i=0;i<n;i++)
  103. if(rev[i]<i)
  104. swap(a[i],a[rev[i]]);
  105. for(i=2;i<=n;i<<=1)
  106. {
  107. wn=fp(g,(p-1)/i);
  108. if(t==-1)
  109. wn=fp(wn,p-2);
  110. for(j=0;j<n;j+=i)
  111. {
  112. w=1;
  113. for(k=j;k<j+i/2;k++)
  114. {
  115. u=a[k];
  116. v=a[k+i/2]*w%p;
  117. a[k]=(u+v)%p;
  118. a[k+i/2]=(u-v)%p;
  119. w=w*wn%p;
  120. }
  121. }
  122. }
  123. if(t==-1)
  124. {
  125. ll inv=fp(n,p-2);
  126. for(i=0;i<n;i++)
  127. a[i]=a[i]*inv%p;
  128. }
  129. }
  130. void getinv(ll *a,ll *b,int n)
  131. {
  132. if(n==1)
  133. {
  134. b[0]=fp(a[0],p-2);
  135. return;
  136. }
  137. getinv(a,b,n>>1);
  138. static ll a1[200000],a2[200000];
  139. int i;
  140. for(i=0;i<n;i++)
  141. a1[i]=a[i];
  142. for(;i<n<<1;i++)
  143. a1[i]=0;
  144. for(i=0;i<n>>1;i++)
  145. a2[i]=b[i];
  146. for(;i<n<<1;i++)
  147. a2[i]=0;
  148. ntt(a1,n<<1,1);
  149. ntt(a2,n<<1,1);
  150. for(i=0;i<n<<1;i++)
  151. a1[i]=(2*a2[i]-a1[i]*a2[i]%p*a2[i])%p;
  152. ntt(a1,n<<1,-1);
  153. for(i=0;i<n;i++)
  154. b[i]=a1[i];
  155. }
  156. void getln(ll *a,ll *b,int n)
  157. {
  158. static ll a1[200000],a2[200000];
  159. int i;
  160. for(i=1;i<n;i++)
  161. a1[i-1]=a[i]*i%p;
  162. a1[n-1]=0;
  163. getinv(a,a2,n);
  164. for(i=n;i<n<<1;i++)
  165. a1[i]=a2[i]=0;
  166. ntt(a1,n<<1,1);
  167. ntt(a2,n<<1,1);
  168. for(i=0;i<n<<1;i++)
  169. a1[i]=a1[i]*a2[i]%p;
  170. ntt(a1,n<<1,-1);
  171. b[0]=0;
  172. for(i=1;i<n;i++)
  173. b[i]=a1[i-1]*inv[i]%p;
  174. }
  175. void getexp(ll *a,ll *b,int n)
  176. {
  177. if(n==1)
  178. {
  179. b[0]=1;
  180. return;
  181. }
  182. getexp(a,b,n>>1);
  183. static ll a1[200000],a2[200000];
  184. int i;
  185. for(i=0;i<n>>1;i++)
  186. a1[i]=b[i];
  187. for(;i<n<<1;i++)
  188. a1[i]=0;
  189. for(i=n>>1;i<n;i++)
  190. b[i]=0;
  191. getln(b,a2,n);
  192. for(i=0;i<n;i++)
  193. a2[i]=-a2[i];
  194. for(i=n;i<n<<1;i++)
  195. a2[i]=0;
  196. a2[0]++;
  197. for(i=0;i<n;i++)
  198. a2[i]=(a2[i]+a[i])%p;
  199. ntt(a1,n<<1,1);
  200. ntt(a2,n<<1,1);
  201. for(i=0;i<n<<1;i++)
  202. a1[i]=a1[i]*a2[i]%p;
  203. ntt(a1,n<<1,-1);
  204. for(i=0;i<n;i++)
  205. b[i]=a1[i];
  206. }
  207. void getpow(ll *a,ll *b,int n,ll k)
  208. {
  209. int d=0;
  210. while(d<n&&!a[d])
  211. d++;
  212. int i;
  213. if(d>=n)
  214. {
  215. for(i=0;i<n;i++)
  216. b[i]=0;
  217. if(!k)
  218. b[0]=1;
  219. return;
  220. }
  221. static ll a1[200000],a2[200000];
  222. ll c=a[d];
  223. ll e=fp(c,p-2);
  224. for(i=0;i<n;i++)
  225. if(i+d<n)
  226. a1[i]=a[i+d]*e%p;
  227. else
  228. a1[i]=0;
  229. getln(a1,a2,n);
  230. for(i=0;i<n;i++)
  231. a2[i]=a2[i]*k%p;
  232. getexp(a2,a1,n);
  233. for(i=0;i<n&&i<d*k;i++)
  234. b[i]=0;
  235. c=fp(c,k);
  236. for(i=d*k;i<n;i++)
  237. b[i]=a1[i-d*k]*c%p;
  238. }
  239. void mul(ll *a,ll *b,ll *c,int n)
  240. {
  241. int i;
  242. static ll a1[200000],a2[200000];
  243. for(i=0;i<n;i++)
  244. {
  245. a1[i]=a[i];
  246. a2[i]=b[i];
  247. }
  248. for(;i<n<<1;i++)
  249. a1[i]=a2[i]=0;
  250. ntt(a1,n<<1,1);
  251. ntt(a2,n<<1,1);
  252. for(i=0;i<n<<1;i++)
  253. a1[i]=a1[i]*a2[i]%p;
  254. ntt(a1,n<<1,-1);
  255. for(i=0;i<n;i++)
  256. c[i]=a1[i];
  257. }
  258. }
  259. using namespace ntt;
  260. ll a[200000],b[200000];
  261. void init()
  262. {
  263. int i;
  264. inv[0]=inv[1]=1;
  265. for(i=2;i<=maxn;i++)
  266. inv[i]=-p/i*inv[p%i]%p;
  267. }
  268. int c;
  269. void gao(ll *a,ll *b,int n)
  270. {
  271. if(n==1)
  272. {
  273. b[0]=0;
  274. return;
  275. }
  276. gao(a,b,n>>1);
  277. int i;
  278. for(i=n>>1;i<n;i++)
  279. b[i]=0;
  280. static ll a1[200000],a2[200000],a3[200000],a4[200000],a5[200000],a6[200000],a7[200000];
  281. //a1=F^(c-1)
  282. getpow(b,a1,n,c-1);
  283. //a2=F^c=a1F
  284. mul(a1,b,a2,n);
  285. //a3=e^F
  286. getexp(b,a3,n);
  287. for(i=0;i<n;i++)
  288. a4[i]=a2[i];
  289. a4[0]++;
  290. mul(a4,a3,a5,n);
  291. for(i=0;i<n;i++)
  292. a5[i]=(a5[i]-a[i])%p;
  293. for(i=0;i<n;i++)
  294. a6[i]=(a2[i]+c*a1[i])%p;
  295. a6[0]++;
  296. mul(a6,a3,a7,n);
  297. getinv(a7,a6,n);
  298. mul(a6,a5,a7,n);
  299. for(i=0;i<n;i++)
  300. b[i]=(b[i]-a7[i])%p;
  301. }
  302. void gao2(ll *a,ll *b,int n)
  303. {
  304. int i;
  305. for(i=0;i<n;i++)
  306. a[i]=a[i]*inv[2]%p;
  307. getln(a,b,n);
  308. }
  309. int n;
  310. int main()
  311. {
  312. init();
  313. open("c");
  314. scanf("%d%d",&n,&c);
  315. int m=1;
  316. while(m<=n)
  317. m<<=1;
  318. int i;
  319. for(i=1;i<=n;i++)
  320. scanf("%lld",&a[i]);
  321. for(i=n+1;i<m;i++)
  322. a[i]=0;
  323. if(!c)
  324. {
  325. a[0]=2;
  326. gao2(a,b,m);
  327. }
  328. else
  329. {
  330. a[0]=1;
  331. gao(a,b,m);
  332. }
  333. for(i=1;i<=n;i++)
  334. {
  335. b[i]=(b[i]+p)%p;
  336. printf("%lld\n",b[i]);
  337. }
  338. return 0;
  339. }

【XSY2680】玩具谜题 NTT 牛顿迭代的更多相关文章

  1. 牛顿迭代,多项式求逆,除法,开方,exp,ln,求幂

    牛顿迭代 若 \[G(F_0(x))\equiv 0(mod\ x^{2^t})\] 牛顿迭代 \[F(x)\equiv F_0(x)-\frac{G(F_0(x))}{G'(F_0(x))}(mod ...

  2. 【loj6538】烷基计数 加强版 加强版 Burnside引理+多项式牛顿迭代

    别问我为啥突然刷了道OI题,也别问我为啥花括号不换行了... 题目描述 求含 $n$ 个碳原子的本质不同的烷基数目模 $998244353$ 的结果.$1\le n\le 10^5$ . 题解 Bur ...

  3. LOJ #6538. 烷基计数 加强版 加强版(生成函数,burnside引理,多项式牛顿迭代)

    传送门. 不妨设\(A(x)\)表示答案. 对于一个点,考虑它的三个子节点,直接卷起来是\(A(x)^3\),但是这样肯定会计重,因为我们要的是无序的子节点. 那么用burnside引理,枚举一个排列 ...

  4. luogu P4726 【模板】多项式指数函数 多项式 exp 牛顿迭代 泰勒展开

    LINK:多项式 exp 做多项式的题 简直在嗑药. 前置只是 泰勒展开 这个东西用于 对于一个函数f(x) 我们不好得到 其在x处的取值. 所以另外设一个函数g(x) 来在x点处无限逼近f(x). ...

  5. [题解]玩具谜题(toy)

    玩具谜题(toy) 来源:noip2016 提高组 day1 [题目描述] 小南有一套可爱的玩具小人, 它们各有不同的职业. 有一天, 这些玩具小人把小南的眼镜藏了起来. 小南发现玩具小人们围成了一个 ...

  6. 玩具谜题(NOIP2016)

    题目链接:玩具谜题 提高组日常水题. 直接模拟,有需要注意的点会在代码后讲解: #include<bits/stdc++.h> using namespace std; int main( ...

  7. HDU.2899.Strange fuction(牛顿迭代)

    题目链接 \(Description\) 求函数\(F(x)=6\times x^7+8\times x^6+7\times x^3+5\times x^2-y\times x\)在\(x\in \l ...

  8. P1563 玩具谜题

    P1563 玩具谜题 题目描述 小南有一套可爱的玩具小人, 它们各有不同的职业. 有一天, 这些玩具小人把小南的眼镜藏了起来. 小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的面朝圈外.如下图: ...

  9. 二分法和牛顿迭代实现开根号函数:OC的实现

    最近有人贴出BAT的面试题,题目链接. 就是实现系统的开根号的操作,并且要求一定的误差,其实这类题就是两种方法,二分法和牛顿迭代,现在用OC的方法实现如下: 第一:二分法实现 -(double)sqr ...

随机推荐

  1. RuntimeError: Model class apps.users.models.User doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.

    报错代码: File "/home/bsodgm/Desktop/Django_projection/mall/apps/users/views.py", line 9, in & ...

  2. 学习用Node.js和Elasticsearch构建搜索引擎(1):了解并运行Elasticsearch

    1.学习Elasticsearch概述. 了解Elasticsearch是什么?能做什么?可以查一下elasticsearch.lucene等的相关介绍,另外也可以查查资料比较一下其它的搜索引擎sph ...

  3. H5 28-优先级之权重问题

    28-优先级之权重问题 我是段落 <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  4. FPGA中边沿触发和电平触发

    边沿触发和电平触发基本就是触发器和锁存器的区别: 触发器是边沿触发,只有当时钟上升(或下降)的一瞬间,触发器会读取并锁存输入信号.输出信号仅在时钟信号上升(或下降)的一瞬间会发生变化.   锁存器是电 ...

  5. iOS-带图片的二维码的生成(QRCode)

    https://blog.csdn.net/feng512275/article/details/82824650 2018年09月23日 20:29:45 筝风放风筝 阅读数:91   版权声明:本 ...

  6. Django 中的Form、ModelForm

    一.ModelForm 源码 class ModelForm(BaseModelForm, metaclass=ModelFormMetaclass): pass def modelform_fact ...

  7. 【kindle笔记】之 《犬夜叉》-2017-12-26

    [kindle笔记]读书记录-总 2017-12-26 <犬夜叉> 买kindle的初衷是看计算机工具书看得眼快瞎了,我弟弟推荐给我的Linux系列<鸟叔私房菜> 真的是深思熟 ...

  8. TortoiseGit push免输密码

    (ฅ>ω<*ฅ) 噫又好了~ TortoiseGit push免输密码的方法 – 晨旭的博客~https://www.chenxublog.com/2016/03/04/tortoiseg ...

  9. MariaDB 和 MySQL 比较

    MariaDB.org - Supporting continuity and open collaborationhttps://mariadb.org/ MariaDB 和 MySQL 比较 - ...

  10. JDBC+Servlet+JSP的学生案例增删改查

    数据库信息传输到页面实现. 先进行学生信息页面展示: 接口IStudentDao public interface IStudentDao { /** * 保存操作 * @param stu 学生对象 ...