[考试反思]0514省选模拟96:对比
来了。又是越考越差的时段。
和昨天是一个出题人,心态先崩一半。
$T1$有了点部分分剩下的还是没有。依然没有构造。依然出现原题($T3$是仓鼠杂题2)
然后比昨天还毒瘤的是今天连大样例都没了。
今天把联考的排行榜粘过来以彰显自己有多菜。
今天主要是时间分配挂了。
$T1$写了三小时半多,$T2$用了$17min$,$T3$用了$10min$。然后浏览器被$oj$卡死提交用了$20min$。剩下时间在摸鱼(放弃挣扎
$T1$最后会正解了但是来不及细想了(因为$T2,3$暴力没打)所以剩下$20$分不要就不要了。
考场上大规模干$T1$就是脑子有问题。(大分类讨论玩得挺欢?
$T2$写了个乱搞本来能过$50$然后因为分配的时间太少写着急了有一个细节挂掉直接就爆零了。(我还以为样例不水)
全世界都没几个爆零的。。。
$T3$原题数学题。没时间了所以打暴力跑路了。结果居然是全场$AC$数最多的题。。
什么乱七八糟的。。。
T1:多边形
大意:求正$n$边形选$m$点构成的多边形恰有$k$锐角的方案数。$n$是奇数。$n \le 10^6,T \le 10^5$
$k>3$无解。
考虑:多边形外角和为$360$。一个锐角对应一个$>90$的外角,故最多$3$个。
我们抽象一下问题:我们要选择$m$个点$1 \le a_1 <a_2 < ... <a_m <n$。满足恰有$k$个$i$满足$a_{i+2}-a_i > \frac{n}{2}$
(序列是循环的,也就是$a_{m+1}=a_1,a+{m+3}=a_2$)
考虑为什么:首先作出原多边形的外接圆,一个你选定的多边形的角$ABC$也就是一个圆周角,则它对应的圆心角是二倍圆周角。
圆周角是锐角所以圆心角小于平角。所以说$a \rightarrow C$这一段弧是一个优弧,至少跨过$\frac{n}{2}$个点。
为了方便下面设$N=\frac{n}{2}$
$k=3$时一定是三角形。此时$m \neq$则无解。
首先三角形的确可能有解。不是三角形的话则需要有三个$i$满足条件,至少有两个$i$的奇偶性相同。
$a_i < a_{i+2} < a_{i+2x} < a_{i+2x+2}$。第$1,3$个小于号的跨度都是$N$。所以$a_{i+2x+2}-a_i>n$就直接非法了。
然后一定是三角形的话,我们固定其中一个点,枚举第二个点的编号,发现第三个点可选位置数是等差数列。直接$O(1)$解决。
$k=2$的话满足条件的两个$i$相差一定是$1$如果差距更大的话可以同上得到总长过长而非法。
我们钦定其中一个$i=1,a_1=1$。计算此时的方案再通过旋转得到其它所有方案。
我们去枚举$a_4$是几。总方案是$\sum\limits_{a_4=N+3}^{n} \binom{n-a_4}{m-4} (a_4-N-2)^2$
就是后边的点随便选,那个平方就是在$a_1,a_4$之间选择$a_2,a_3$的方案数。
考虑组合含义优化:我们在$[N+2,n]$里选择$a_4$,$n-a_4$个元需里选$m-2$个,再在$a_4-N-2$个元素里可重复选两个。
分类讨论你可重复选的那两个是否重复了:
重复那就是一共在$[N+2,n]$里随便选$m-3$个然后钦定其中第二个是$a_4$。方案一一对应。直接组合数。
不重复那就多选一个,考虑到顺序问题还要乘$2$。
特殊处理$m=3$。这样$k=2$就可以$O(1)$解决。
$k=1$的话我采用的方法是:计数所有多边形的锐角个数和再减去$k \ge 2$的方案的贡献。
所以我们再次钦定一个锐角$i=1,a_1=1$。
这回只需要枚举$a_3 > N+1$。方案数就是$\binom{n-a_3}{m-3} (a_3-2)$
还是组合含义优化,分类讨论$a_2 >N+1$与否,组合数加上组合数乘系数。
$k=0$的情况就是所有情况减去上边这些情况。
总时间复杂度$O(n+T)$
1 #include<cstdio> 2 const int mod=1000109107,S=1000005; 3 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;} 4 int n,m,t,k,fac[S],inv[S]; 5 int C(int b,int t){return t<0||t>b?0:fac[b]*1ll*inv[t]%mod*inv[b-t]%mod;} 6 int cal3(int n,int m){return m==3?n*(n+1ll)*(2*n+1)/6%mod:0;} 7 int cal2(int n,int m){ 8 if(m==3)return (mod+C(n+n+1,3)-cal3(n,m))%mod; 9 return (2ll*C(n,m-1)+C(n,m-2))*(1ll+n+n)%mod; 10 } 11 int cal1(int n,int m){ 12 int ans=(C(n,m-2)*1ll*n+C(n,m-1))%mod; 13 return ((ans*(1ll+n+n)-2*cal2(n,m)%mod-3ll*cal3(n,m))%mod+mod)%mod; 14 } 15 int main(){ 16 for(int i=fac[0]=1;i<S;++i)fac[i]=fac[i-1]*1ll*i%mod; 17 inv[S-1]=qp(fac[S-1],mod-2); 18 for(int i=S-2;~i;--i)inv[i]=inv[i+1]*(i+1ll)%mod; 19 scanf("%d",&t);while(t--){ 20 scanf("%d%d%d",&n,&m,&k); 21 n>>=1; 22 if(k>3)puts("0"); 23 else if(k==3)printf("%d\n",cal3(n,m)); 24 else if(k==2)printf("%d\n",cal2(n,m)); 25 else if(k==1)printf("%d\n",cal1(n,m)); 26 else printf("%lld\n",(mod*3ll+C(n+n+1,m)-cal1(n,m)-cal2(n,m)-cal3(n,m))%mod); 27 } 28 }
T2:仙人掌
大意:树,每次操作会使某个点所有邻居权值$+1$并询问所有邻居权值异或和。$n,Q \le 5 \times 10^5$
每次$+1$的话那么子树里所有节点的权值最多有$O(\sqrt{m})$种。
所以直接开一个$unordered-set$暴力维护子树中所有点的权值及出现次数,复杂度$O(n\sqrt{n})$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define f1 first 4 #define s2 second 5 const int mod=1000109107,S=1000005; 6 int n,m,ans,fir[S],l[S],to[S],ec,f[S],ts[S],tf[S]; 7 unordered_map<int,int>M[S],R; 8 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;} 9 void dfs(int p,int fa){ 10 f[p]=fa; M[fa][0]++; 11 for(int i=fir[p];i;i=l[i])if(to[i]!=fa)dfs(to[i],p); 12 } 13 int addson(int p){ 14 int a=0; 15 for(auto x:M[p])R[x.f1+1]=x.s2,a^=x.s2&1?x.f1+1:0; 16 swap(M[p],R);R.clear(); return a; 17 } 18 int addfa(int p){ 19 if(!p)return 0; 20 int a=tf[p]+ts[f[p]]; 21 int&x=M[f[p]][a];x--; if(!x)M[f[p]].erase(M[f[p]].find(a)); 22 M[f[p]][a+1]++; return a+1; 23 } 24 int main(){ 25 scanf("%d%d",&n,&m); 26 for(int i=1,a,b;i<n;++i)scanf("%d%d",&a,&b),link(a,b),link(b,a); 27 dfs(1,0); 28 for(int _=1,x;_<=m;++_) 29 scanf("%d",&x), 30 ans=(ans+(1ll*_*_+_)%mod*(addson(x)^addfa(f[x])))%mod, 31 ts[x]++,tf[f[x]]++; 32 printf("%d\n",ans); 33 }
正解是,发现一个数$+1$相当与异或上$2^{z+1}-1$。$z$是最低的$0$位。
按从低位到高位维护$trie$表示儿子的所有权值。每次跑$1$方向修改并更新答案。$O(nlogn)$
T3:多项式
大意:有$n$个$0 <x\le T$的变量和$m$个$0<x$的变量,其和$\le S$。求方案数。$n \le 10^9,m \le 10^3,nT \le S \le 10^{18},T \le 10^9$
首先为了方便去掉$\le S$的限制所以我们可以新增一个不限制的变量,也就是说$m++$。为了让它也满足$x>0$需要让$S++$
可以列出这样一个基础式子$\sum\limits_{x_{1...n},\sum a =x} \binom{S-x}{m}$
组合数化成下降幂除阶乘,阶乘可以拿出来单算。然后我们有
$n^{\underline{m}} = \sum\limits_{i=0}^{m} (-1)^{m-i} \begin{bmatrix} m \\ i\end{bmatrix} n^i$
也就有我们要求的是$\frac{1}{m!} \sum\limits_{\sum a_i = x} \sum\limits_{i=0}^{m} \begin{bmatrix} m \\ i \end{bmatrix} (-1)^{m-i} (S-x)^i$
最后那个东西二项式展开一下
$\frac{1}{m!} \sum\limits_{\sum a_i = x} \sum\limits_{i=0}^{m} \begin{bmatrix} m \\ i \end{bmatrix} (-1)^{m-i} \sum\limits_{j=0}^{i} S^{i-j}(-1)^j x^j$
这样就只有最后一项与$x$有关了。我们要求的形如下式:
$A_j = \sum\limits_{\sum\limits_{i=1}^{n} a_i = x} x^j$
设$F_{k,j} = \sum\limits_{\sum\limits_{i=1}^{k} a_i = x} x^j$
根据二项式展开那一套,有$F_{x+y,i+j} = \sum F_{x,i} F(y,j) \binom{i+j}{i}$
所以可以直接倍增$F$求出$A$。$F_{0,i}$就是简单的自然数幂和。随便怎么做都行。
式子逐层处理即可。时间复杂度$O(m^2logn)$
1 #include<cstdio> 2 #define ll long long 3 const int mod=1000109107,S=1005; 4 int n,m,t,fac[S],ans,F[31][S],A[S],st[S][S],St[S][S],C[S][S],iv[S],G[S],pws[S];ll s; 5 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;} 6 int Spw(int n,int k,int a=0){for(int i=0,C=1+n;i<=k;++i)a=(a+1ll*St[k][i]*fac[i]%mod*C)%mod,C=1ll*C*(n-i)%mod*iv[i+2]%mod;return a;} 7 int main(){ 8 for(int i=fac[0]=iv[1]=1;i<S;++i)fac[i]=fac[i-1]*1ll*i%mod; 9 for(int i=2;i<S;++i)iv[i]=mod-mod/i*1ll*iv[mod%i]%mod; 10 for(int i=st[0][0]=St[0][0]=C[0][0]=1;i<S;++i)for(int j=C[i][0]=1;j<=i;++j) 11 st[i][j]=(st[i-1][j]*(i-1ll)+st[i-1][j-1])%mod, 12 St[i][j]=(St[i-1][j]*1ll*j+St[i-1][j-1])%mod, 13 C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; 14 scanf("%lld%d%d%d",&s,&t,&n,&m); m-=n; s%=mod; 15 for(int i=0;i<=m;++i)F[0][i]=Spw(t,i); F[0][0]--; 16 for(int i=1;1<<i<=n;++i)for(int j=0;j<=m;++j)for(int k=0;k+j<=m;++k) 17 F[i][j+k]=(F[i][j+k]+1ll*F[i-1][j]*F[i-1][k]%mod*C[j+k][j])%mod; 18 for(int i=0;i<=30;++i)F[i][0]--; 19 A[0]=1; 20 for(int i=0;1<<i<=n;++i)if(n>>i&1)for(int j=m;~j;--j)for(int k=m-j;~k;--k) 21 A[j+k]=(A[j+k]+1ll*A[j]*F[i][k]%mod*C[j+k][j])%mod; 22 for(int i=pws[0]=1;i<=m;++i)pws[i]=pws[i-1]*1ll*s%mod; 23 for(int i=0;i<=m;++i)for(int j=0;j<=i;++j) 24 G[i]=(G[i]+(j&1?mod-1ll:1ll)*pws[i-j]%mod*A[j]%mod*C[i][j])%mod; 25 for(int i=0;i<=m;++i)ans=(ans+(m-i&1?mod-1ll:1ll)*st[m][i]%mod*G[i])%mod; 26 printf("%lld\n",ans*1ll*qp(fac[m],mod-2)%mod); 27 }