Provider: Another_Misaki
NO.1 uwi
NO.2 hongrock
NO.3 z286830682
[title]A: Ferries Wheel[/title] 题意:有$N$个人去做摩天轮,每个人进一个缆车,问有多少人满足:【(他的缆车的值+左边车的值)%INT_MAX=右边缆车的值】. 解法:暴力,记录每个缆车出现的次数,排序去重,枚举缆车的值,判断是否满足那个等式即可。 HACK点:题目没告诉你输入是有重复数的(开始没有样例3,担心被喷得太惨,就加了样例3),只有一个缆车的情况不一定只是$N=1$. [title]B: Misaki's Kiss again[/title] 题意:找出$0$到$N-1$中,有哪些数满足$gcd(N,M)==N xor M$. 解法:暴力枚举$N$的所有约数$K$,令$M=N xor K$,再判断$gcd(N,M)$是不是等于$K$。时间$O(sqrt(N))$; HACK点:有些人可能会一不小心枚举的时候定义成了int.导致$i*i$成负数。 [title]C:The Experience of Love[/title] 题意:给一棵树,求任意{两点路径上的最大边权值-最小边权值}的总和。 解法:$sigma(maxVal[i]-minVal[i])=sigma(maxVal)-sigma(minVal)$;所以我们分别求所有两点路径上的最大值的和,还有最小值的和。再相减就可以了。求最大值的和的方法用带权并查集,把边按权值从小到大排序,一条边一条边的算,当我们算第$i$条边的时候权值为$wi$,两点是$ui,vi$,前面加入的边权值一定是小于等于当前$wi$的,假设与$ui$连通的点有$a$个,与$vi$连通的点有$b$个,那么在$a$个中选一个,在$b$个中选一个,这两个点的路径上最大值一定是$wi$,一共有$a*b$个选法,爱情经验值为$a*b*wi$。 求最小值的和的方法类似。 槽点: 一:这题做数据的时候突然想到的把数据范围设在 unsigned long long 范围内,要爆 long long,这样选手在wa了之后可能心态不好找不到这个槽点,当是锻炼大家的心态和出现wa时的找错能力了,把这放在pretest..很良心的。 二,并查集的时候,用是递归的需要扩栈,一般上$10w$的递归都需要,所以看见有几个FST在栈溢出的,好桑心。 [title]D:Box[/title] 可以把两个人的箱子数目对应到二维坐标中,由于条件限定,第二个人的箱子数目不能多于第一个人,所有的方法数也就是从(0,0)点走到(n,n)点不跨越x=y这一条直线的所有方法数。这是一个经典的问题,他的答案是卡特兰数$\frac{{\rm{1}}}{{n + 1}}C_{2n}^n$. 现在要将这个数字对M=3814697265625取余,n又特别大。那得看看这个数字有什么特殊性。尝试着将M进行质因数分解,发现M=5^18 那么首先计算一下$\frac{{\rm{1}}}{{n + 1}}C_{2n}^n$有多少个5因子。如果>=18结果就是0了。 如果小于18,就要计算$\frac{{\rm{1}}}{{n + 1}}C_{2n}^n$不含5的的部分对M取余。 对于前半部分$\frac{{\rm{1}}}{{n + 1}}$好处理。直接把5除掉,求逆元即可。 对于$C_{2n}^n$先转化一下,$C_{2n}^n = \frac{{(2n)!}}{{n!*n!}}$,现在关键问题是求n!里面不含5的对M取余的结果。 设f(n!)代表n!里面不含5的对M取余的结果 可以用多项来解决这个问题。g(x,n)=(x+1)(x+2)(x+3)(x+4)(x+6)..(x+n)%M,x+d里面的d不是5的倍数。 那么f(n!)=g(0,n)*g(0,n/5)*g(0,n/25)*…*g(0,0)%M 现在的问题关键是如何快速求g(x,n)。 我们可以把g(x,n)分成尽量均匀的两段来计算 Seg1=(x+1)(x+2)(x+3)(x+4)(x+6)*…*(x+5*k-1) Seg2=(x+5*k+1)(x+5*k +2)(x+5*k +3)(x+5*k +4)(x+5*k +6)*…*(x+5*k +5*k-1) 当然末尾还有几项,不过项数不超过10,所以直接暴力乘上来就可以了。 先计算出第一段,然后把5*k+x代入第一段就可以得到第二段,因为我们的x是5的倍数,所以x^18以上的项数对M取余是0的,所以只要保留低18项即可。 这样计算f(n!)的复杂度是log(n)*log(n)*18*18*18,第一个log(n)是除5造成的,第二个log(n)是求多项式乘积产生的,后面两个18是多项式乘法,还有一个18是高精度乘法带来的。
Provider: iamzky
NO.1 anta
NO.2 uwi
NO.3 alpq654321
[title]1001 GTY's math problem[/title] 取对数比较就好了$log(a^b)=b*log(a)$,注意会有精度误差 [title]1002 GTY's birthday gift[/title] 显然每次会从可重集中选择最大的两个进行操作,设这两数为$a,b(a>=b)$,操作之后的数一定是操作后集合中最大的,下一次选取的数一定是$a+b$和$a$,这就形成了一个类似于斐波那契数列的东西,矩阵乘法快速幂求前n项和即可,转移矩阵如下 $$ \begin{bmatrix} 1 & 1 &1 \\ 0 & 1 &1 \\ 0 & 1 & 0 \end{bmatrix} \begin{bmatrix} S_{n-1}\\ F_{n-1}\\ F_{n-2} \end{bmatrix} = \begin{bmatrix} S_n\\ F_n\\ F_{n-1} \end{bmatrix} $$ [title]1003 GTY's gay friends[/title] 一个区间是排列只需要区间和为$\frac{len(len+1)}{2} $($len$为区间长度),且互不相同,对于第一个问题我们用前缀和解决,对于第二个问题,预处理每个数的上次出现位置,记它为pre,互不相同即区间中pre的最大值小于左端点,使用线段树或Sparse Table即可在$O(n)/O(nlogn)$的预处理后 $O(logn)/O(1)$回答每个询问.不过我们还有更简单的hash做法,对于$[1..n]$中的每一个数随机一个64位无符号整型作为它的hash值,一个集合的hash值为元素的异或和,预处理$[1..n]$的排列的hash和原序列的前缀hash异或和,就可以做到线性预处理,$O(1)$回答询问. [title]1004 GTY's game II[/title] 对于序列来说,区间翻转和区间和是Splay的经典操作,而把这个问题扩展到树上,我们只需要对这棵树进行树链剖分,分成$O(logn)$的区间,使用Splay维护即可,单次询问复杂度$O(log^2n)$,请注意使用递归的树链剖分有可能爆栈.我们还可以用Link-Cut Tree来解决,分别维护两棵LCT,一棵维护形态一棵维护值,对不同的操作分别维护即可. P.S. 感谢gaotianyu1350的题面和翻译,感谢验题人hzwer,bakser,感谢Herobs的帮助
Provider: sd0061
NO.1 anta
NO.2 sandytea
NO.3 ztxz16
[title]1001 Missing number[/title] 直接开一个数组记录某个数字是否出现过,就能找到没有出现的两个数字了。更好的空间为$O(1)$的做法是用$n(n+1) \over 2$减去出现数字可以得到两个数字的和,同理一样的方法也可以得到两个数字的平方和,就能解出这两个数字了。 [title]1002 Fibonacci[/title] Fibonacci序列在$10^9$范围内只有43个数,则它们的乘积不超过$10^9$的数也不会很多,直接搜索即可。 [title]1003 Legal path[/title] 虽然看起来是一道最短路模型的题目,但由于要求了走的边权要递增,就可以设计出动态规划的做法。 先将所有边按照边权排序,要找的就是边列表的一个子序列,使得子序列中所有边起点为1,终点为n,其他边起点终点相连,边权递增且差不小于K。就可以得到一个动态规划的做法,暴力是$O(m^2)$的,而转移的过程每次只针对一个点的所有出边,可以给每个点维护一个随着上一条边的权值上升而总代价减小的栈,就可以把DP的复杂度降低为$O(n+m)$,当然因为要排序,再带一个log也是没问题的。 [title]1004 Flipping coins[/title] 比较常规的题目,建立出两个串构成的自动机以及状态转移,就可以按照题意列出方程,高斯消元即可。这样做是$O((|A|+|B|)^3)$的。 但是题目中需要考虑平局的情况,用double来做高斯消元的精度是完全不够的,一种可行的方案是写一个分数类再高斯消元,当然这里分子分母也需要用高精度,需要比较好的实现。 这道题目是一个游戏的改编:https://en.wikipedia.org/wiki/Penney%27s_game 除此之外还有一个利用KMP的$O(|A|+|B|)$的做法,需要比较繁琐的数学推导,这里就把范围没有设的那么大。
Provider: zimpha
NO.1 ztxz16
NO.2 KirinoP
NO.3 kutengine
[title]1001 Jump and Jump...[/title] 首先算出每个人的成绩,然后sort一下就好了,考虑$n$的范围只有2或者3,只要用if+swap也是可行的。 [title]1002 Taking Bus[/title] 简单的分类讨论,设$s,x,y$分别表示公交的始发站,起点和终点。大概有这样几种情况:1. $s \le x < y$, 2. $x < s < y$,3. $x < y \le s$, 4. $s \le y < x$, 5. $y < s < x$, 6. $y < x \le s$ 分别写出公式即可。答案应该会超过int,注意要用long long。 [title]1003 Matching on Array[/title] 首先我们考虑$m=1$的情况。给定两个数组$A=\{a_1,a_2,\dots,a_n\}$和$B=\{b_1,b_2,\dots,b_k\}$,问$B$在$A$中出现了几次。令$c_i=\frac{a_{i+1}}{a_i}, 1 \le i < n$,同样令$d_i=\frac{b_{i+1}}{b_i}, 1 \le i < k$,那么上述问题可以转化为$c_i$和$d_i$的模式匹配问题,这个正确性显然,也没有什么好证明的。于是对于$m=1$的情况只有用个kmp即可搞定。 现在考虑$m > 1$的情况,我们考虑用ac自动机来做。考虑到字符集并不是普通的数字,而是一个分数,我们不放搞个分数类,然后用map存转移边。用$m$个模式串(Bob的序列)建好自动机之后,把文本串(Alice的序列)在自动机上跑一遍即可统计出答案。 [title]1004 Funny Game[/title] 题目要求对于任何初始状态都要必胜,我们先把这个条件简化一下,毕竟我们不可能枚举所有的初始状态(总共n!个)。 我们先考虑$\{1,2,\dots,n\}$这个状态的必胜条件——对于任意一对数$(x,y), 1 \le x, y \le n$, Alice都能都把它们变成相同的数。这个条件也显然是充分必要的,随便想想就明白了。然后我们可以发现,如果$\{1,2,\dots,n\}$这个状态能够必胜的话,其他的状态也显然能够必胜。如果这个状态不能够必胜,那根本不需要考虑其他状态了。 于是我们只需要考虑是否对于任意一对数$(x,y), 1 \le x, y \le n$, Alice都能都把它们变成相同的数。这样的状态数只有$O(n^2)$个,我们可以考虑dp来做。先用题目给定的$m$个函数构造出一张有向图,图中每个节点都是数对。仔细想想就会发现我们不能用普通的博弈思路来做,因为这个博弈会形成环,这时候我们考虑从终结状态往回推,得出每个状态的dp值。 令dp[i][j][0/1]表示数对为$(i,j)$,Alice先(1)后(0)手是否必胜。然后我们知道dp[i][i][0/1]都是必胜的,并把这些状态放入队列。我们依次从队列中取出一个状态$(x,y,turn)$,如果$turn=1$,那么这个状态的前驱是Bob的回合,不妨设为$(a,b,0)$,那么如果$(a,b,0)$的后继状态都是Alice必胜的话,那么dp[a][b][0]显然也是Alice必胜的,否则这个状态的值我们目前无法确定。如果$turn=0$,类似的那么这个状态的前驱是Alice的回合,不妨设为$(a,b,1)$,那么如果$(a,b,1)$的后继中有一个状态是Alice必胜的,那么dp[a][b][1]显然也是Alice必胜,考虑到$(x,y,0)$就是Alice必胜的,那么前驱状态$(a,b,1)$必然是Alice必胜。我们每次把必胜状态加入队列,用来更新那些未确定的状态。 最后统计是否每个$(x,y,1)$的状态都是必胜的,如果是那么Alice输出YES,否则输出NO。时间复杂度的话是$O(n^3)$。
Provider: bayygy
NO.1 JayYe
NO.2 kutengine
NO.3 anta
[title]1001 Have meal[/title] This is an easy problem. We can find the regular pattern through simulating some small cases. So we can find that the answer is (m-1) % n. Another way to solve this problem is dynamic programming. dp[i][j] indicates the answer of i messes and j words. So the boundary condition are dp[i][1]=0. The transfer formula is dp[i][j]=(dp[i][j-1]+1)%i; . Thus we can preprocess all answers with time complexity of O (100*100). [title]1002 Card[/title] 设Xi代表分数为i的牌在b次操作中是否被选到,Xi=1为选到,Xi=0为未选到 那么期望EX=1*X1+2*X2+3*X3+…+x*Xx Xi在b次中被选到的概率是1-(1-1/x)^b 那么E(Xi)= 1-(1-1/x)^b 那么EX=1*E(X1)+2*E(X2)+3*E(X3)+…+x*E(Xx)=(1+x)*x/2*(1-(1-1/x)^b) [title]1003 Apple[/title] 数据规模比较大,直接暴力行不通。可以对不同的数字进行独立的处理。 先对数据进行排序,然后把每一种数字有多少个统计一下。 因为对于比当前小的数字是不影响当前数字是否被统计的。所以可以只考虑比当前数字大的,记当前要统计的是第i种数字,数字为x,有y个,比当前数字大的有tot个,总共有n个数字。可以先从n个位置中选出y+tot个位置给当前数字和比当前数字大的数。剩下的位置给前面i-1种数字放,前面i-1种数字的排列数可以通过多重集排列轻松计算出来。Dp[i]代表前i种数字的排列数。Dpr[i]代表后i种数字的排列数。接下来就是计算当前数字有几个个被统计进去了。 可以枚举当前数字被统计进去的数目那么数字x被统计进去的总和是 C(n,y+tot)*Dp[i-1]*x*(y+(y-1)*c(tot,1)+(y-2)*c(tot+1,2)+…+1*c(tot+y-2,y-1))*dpr[i+1] C(i,j)为组合数从i个中选j个的方法数。 最后总的复杂度是O(nlogn) [title]1004 Mathematics problem[/title] 这是一个二阶常系数齐次微分方程。 $\left\{\begin{matrix}{f{\left( x \right)}}^{"}=f{\left( x \right)}\\ {f{\left( 0 \right)}=f{\left( 0 \right)}}^{'}=1\end{matrix}\right.$ 先得出特征方程${\lambda ^{\rm{2}}}{\rm{ - }}1{\rm{ = }}0$ 解出$\lambda {\rm{ = }} \pm 1$ 那么$f\left( x \right) = {C_1}{e^x} + {C_2}{e^{ - x}}$ 将初值代入得$f\left( x \right) = {e^x}$ 那么$g\left( x \right) = \frac{x}{{{e^x} - 1}}$ 直接求导很麻烦,可以采用泰勒展开$g\left( x \right) = \sum\limits_{n = 0}^\infty {{a_n}{x^n}} $ 那么 $\mathop {\lim }\limits_{x \to 0} {\kern 1pt} {\kern 1pt} {\kern 1pt} g{\left( x \right)^{\left( n \right)}}$$ = n! * {a_n}$ $g\left( x \right) = \frac{x}{{{e^x} - 1}} = \frac{x}{{\sum\limits_{n = 1}^\infty {\frac{{{x^n}}}{{n!}}} }} = \frac{1}{{\sum\limits_{n = 1}^\infty {\frac{{{x^{n - 1}}}}{{n!}}} }}$ 然后再用FFT求出${\sum\limits_{n = 1}^\infty {\frac{{{x^{n - 1}}}}{{n!}}} }$在MOD x^65536意义下的多项式逆,即可求出前面65536个an了。 多项式的逆可以用倍增法。 设Bt为多项A在模x^t意义下的逆 那么 \[\begin{array}{l} {B_t}*A = 1(mod{\kern 1pt} {\kern 1pt} {x^t})\\ {B_{2t}}*A = 1(mod{\kern 1pt} {\kern 1pt} {x^t}) \end{array}\] 那么有\[{{\rm{B}}_{\rm{t}}} - {B_{2t}} = 0(mod{\kern 1pt} {\kern 1pt} {\kern 1pt} {x^t})\] 两边平方\[{{\rm{B}}^2}_{\rm{t}} - 2{{\rm{B}}_{\rm{t}}}{B_{2t}} + B_{2t}^2 = 0(mod{\kern 1pt} {\kern 1pt} {\kern 1pt} {x^{{\rm{2}}t}})\] 左右两边同乘A \[{\rm{A*}}{{\rm{B}}^2}_{\rm{t}} - 2{{\rm{B}}_{\rm{t}}} + B_{2t}^{} = 0(mod{\kern 1pt} {\kern 1pt} {\kern 1pt} {x^{{\rm{2}}t}})\] 所以\[B_{2t}^{}{\rm{ = - A*}}{{\rm{B}}^2}_{\rm{t}}{\rm{ + }}2{{\rm{B}}_{\rm{t}}}(mod{\kern 1pt} {\kern 1pt} {\kern 1pt} {x^{{\rm{2}}t}})\] 初始条件 这样就可以在nlogn时间内求出多项式的逆了。 ```cpp #include <iostream> #include<stdio.h> #include<algorithm> #include<math.h> #include<string.h> using namespace std; typedef __int64 lld; const int MAX=65536*4; const int MOD=1000000007; void outmat(int a[],int len) { return; for(int i=0;i<len;i++)printf("%d ",a[i]); puts(""); } int P[3],g[3]; int r[3][MAX],tb[MAX]; bool isprime(int n) { int i; for(i=2;i*i<=n;i++)if(n%i==0)return false; return true; } lld mod(lld a,lld b,lld m) { lld ret=1; a%=m; while(b) { if(b&1)ret=ret*a%m; a=a*a%m; b>>=1; } return ret; } bool isroot(int g,int P) { int p1=P-1,i; for(i=1;i*i<=p1;i++) { if(p1%i==0) { if(mod(g,i,P)==1)return false; if(p1/i<p1&&mod(g,p1/i,P)==1)return false; } } return true; } void init(int lim) { int cnt=0,k=1; for(cnt=0;cnt<3;cnt++) { while(true) { P[cnt]=k<<21|1; if(P[cnt]>lim&&isprime(P[cnt])) { for(g[cnt]=1;isroot(g[cnt],P[cnt])==false;g[cnt]++) ; k++; break; } k++; } } } int rev(int n,int bitcnt) { int ret=0; while(bitcnt--) { ret=ret<<1|(n&1); n>>=1; } return ret; } void buildleaf(int a[],int bitcnt) { int full=1<<bitcnt; int i,j; for(i=0;i<full;i++) { j=rev(i,bitcnt); if(j<i)swap(a[i],a[j]); } } void FFT(int a[],int bitcnt,int mode,int P,int g) { buildleaf(a,bitcnt); int s,half; int i,k,full=1<<bitcnt; for(s=2;s<=full;s<<=1) { half=s>>1; lld wn=mod(g,(P-1)/s,P); if(mode==-1)wn=mod(wn,s-1,P); for(i=0;i<full;i+=s) { lld w=1; for(k=0;k<half;k++) { lld u=a[k+i]; lld v=w*a[k+i+half]; if(v>=P)v%=P; if(u+v>=P)a[k+i]=u+v-P; else a[k+i]=u+v; a[k+i+half]=u-v; if(a[k+i+half]<0)a[k+i+half]+=P; w=w*wn%P; } } } if(mode==-1) { lld iv=mod(full,P-2,P); lld tmp; for(i=0;i<full;i++) { tmp=iv*a[i]; if(tmp>=P)tmp%=P; a[i]=tmp; } } } lld CRT(lld r0,lld r1,lld r2,lld p0,lld p1,lld p2) { lld invp0p1=423765473; lld invp0=253231225; lld t0=(r1-r0)*invp0; if(t0>=p1||t0<=-p1)t0%=p1; if(t0<0)t0+=p1; lld y=t0*p0+r0; lld k=(r2-y); if(k>=p2||k<=-p2)k%=p2; k*=invp0p1; if(k>=p2||k<=-p2)k%=p2; if(k<0)k+=p2; lld res=k*p0; if(res>=MOD)res%=MOD; res=(res*p1+y)%MOD; return res; } bool zero(int a[],int n) { for(int i=0;i<n;i++)if(a[i])return false; return true; } bool one(int a[],int n) { if(a[0]!=1)return false; return zero(a+1,n); } int conv(int a[],int b[],int n,int m,int up) { int bitcnt=0; int i,j; if(zero(a,n)) { return n; } else if(zero(b,m)) { a[0]=0; return 1; } else if(one(b,m))return n; else if(one(a,n)) { memcpy(a,b,sizeof(int)*m); return m; } while((1<<bitcnt)<n+m)bitcnt++; int full=1<<bitcnt; for(i=n;i<full;i++)a[i]=0; for(i=m;i<full;i++)b[i]=0; for(i=0;i<3;i++) { memcpy(r[i],a,sizeof(int)*full); memcpy(tb,b,sizeof(int)*full); FFT(r[i],bitcnt,1,P[i],g[i]); FFT(tb,bitcnt,1,P[i],g[i]); lld tmp=0; for(j=0;j<full;j++) { tmp=(lld)tb[j]*r[i][j]; if(tmp>=P[i])tmp%=P[i]; r[i][j]=tmp; } FFT(r[i],bitcnt,-1,P[i],g[i]); } for(i=0;i<full&&i<up;i++) { a[i]=CRT(r[0][i],r[1][i],r[2][i],P[0],P[1],P[2]); } while(i>0&&a[i-1]==0)i--; return i; } lld inv[MAX],invfac[MAX],fac[MAX]; lld B[MAX]; int A[MAX],B0[MAX]; int TA[MAX],TB[MAX]; void minu(int a[],int n) { int i; for(i=0;i<n;i++) { a[i]=-a[i]+MOD; if(a[i]==MOD)a[i]=0; } a[0]+=2; if(a[0]>=MOD)a[0]-=MOD; } int main() { init(1000000000); int i,j; int up=65536; inv[0]=inv[1]=1; invfac[0]=invfac[1]=1; fac[0]=fac[1]=1; for(i=2;i<MAX;i++) { inv[i]=-inv[MOD%i]*(MOD/i)%MOD+MOD; invfac[i]=invfac[i-1]*inv[i]%MOD; fac[i]=fac[i-1]*i%MOD; } for(i=0;i<up;i++) { A[i]=invfac[i+1]; } B0[0]=1; int m=up; for(m=2;m<=up;m<<=1) { memcpy(TA,A,sizeof(int)*m); memcpy(TB,B0,sizeof(int)*(m>>1)); conv(TA,TB,m,m>>1,m); minu(TA,m); conv(B0,TA,m>>1,m,m); } for(i=0;i<up;i++) { lld tmp=fac[i]*B0[i]; if(tmp>=MOD)tmp%=MOD; B[i]=tmp; } lld n; while(scanf("%I64d",&n)!=EOF) { printf("%I64d\n",B[n]); } return 0; } ```