省选测试41
总结
(T1,T3) 都是推式子的题,(T2) 是一个套路题,之前没有见过。
A. 多边形
分析
(k>3) 时无解,因为多边形外角和为(360)。一个锐角对应一个(>90)的外角,故最多(3)个。
对于 (k leq 3) 的情况大力分类讨论即可。
代码
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
#define rg register
template<typename T>void read(rg T& x){
x=0;rg int fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
x*=fh;
}
const int maxn=1e6+5,mod=1000109107;
inline int addmod(rg int now1,rg int now2){
return now1+=now2,now1>=mod?now1-mod:now1;
}
inline int delmod(rg int now1,rg int now2){
return now1-=now2,now1<0?now1+mod:now1;
}
inline int mulmod(rg long long now1,rg int now2){
return now1*=now2,now1>=mod?now1%mod:now1;
}
int t,n,m,k,jc[maxn],jcc[maxn],ny[maxn];
void pre(){
ny[1]=1;
for(rg int i=2;i<maxn;i++) ny[i]=mulmod(mod-mod/i,ny[mod%i]);
jc[0]=jcc[0]=1;
for(rg int i=1;i<maxn;i++) jc[i]=mulmod(jc[i-1],i),jcc[i]=mulmod(jcc[i-1],ny[i]);
}
int getC(rg int nn,rg int mm){
if(nn<mm) return 0;
return mulmod(jc[nn],mulmod(jcc[mm],jcc[nn-mm]));
}
int getsum(rg int now){
return mulmod(now,mulmod(now+1,ny[2]));
}
int solve3(){
if(m!=3) return 0;
else return delmod(getC(n,m),mulmod(n,getsum(n/2-1)));
}
int solve2(){
if(m==3) return mulmod(n,getsum(n/2-1));
else return mulmod(n,addmod(mulmod(2,getC(n/2,m-1)),getC(n/2,m-2)));
}
int solve1(){
rg int ans=addmod(mulmod(getC(n/2,m-2),n/2),getC(n/2,m-1));
ans=delmod(mulmod(ans,n),addmod(mulmod(2,solve2()),mulmod(3,solve3())));
return ans;
}
int solve0(){
return delmod(getC(n,m),addmod(solve1(),addmod(solve2(),solve3())));
}
int main(){
pre();
read(t);
while(t--){
read(n),read(m),read(k);
if(k>=4) printf("0
");
else if(k==3) printf("%d
",solve3());
else if(k==2) printf("%d
",solve2());
else if(k==1) printf("%d
",solve1());
else printf("%d
",solve0());
}
return 0;
}
B. 仙人掌
分析
什么乱七八糟的仙人掌,就是一棵树。
对于每一个点开一颗 (trie) 树维护子树内的异或和,支持整体加一、删除一个数、加入一个数。
由低位到高位建 (trie),整体加一的时候相当于把最低位的一个 (0) 变成 (1),把后面所有的 (1) 都翻转成 (0)。
具体实现的时候就是交换左右儿子,递归 (0) 的那一部分子树。
代码
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
#define rg register
template<typename T>void read(rg T& x){
x=0;rg int fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
x*=fh;
}
const int maxn=1e6+5,mod=1000109107;
inline int addmod(rg int now1,rg int now2){
return now1+=now2,now1>=mod?now1-mod:now1;
}
inline int delmod(rg int now1,rg int now2){
return now1-=now2,now1<0?now1+mod:now1;
}
inline int mulmod(rg long long now1,rg int now2){
return now1*=now2,now1>=mod?now1%mod:now1;
}
int h[maxn],tot=1,n,m,tag[maxn],a[maxn],fa[maxn],ans;
struct asd{
int to,nxt;
}b[maxn];
void ad(rg int aa,rg int bb){
b[tot].to=bb;
b[tot].nxt=h[aa];
h[aa]=tot++;
}
void dfs(rg int now,rg int lat){
fa[now]=lat;
for(rg int i=h[now];i!=-1;i=b[i].nxt){
rg int u=b[i].to;
if(u==lat) continue;
dfs(u,now);
}
}
int rt[maxn],ch[maxn*10][2],sum[maxn*10],num[maxn*10],cnt;
void push_up(rg int da,rg int bit){
num[da]=num[ch[da][0]]+num[ch[da][1]];
sum[da]=sum[ch[da][0]]^sum[ch[da][1]];
if(num[ch[da][1]]&1) sum[da]^=(1<<(bit-1));
}
void insert(rg int &da,rg int val,rg int bit){
if(!da) da=++cnt;
if(bit>20){
num[da]++;
return;
}
if(val&(1<<(bit-1))) insert(ch[da][1],val,bit+1);
else insert(ch[da][0],val,bit+1);
push_up(da,bit);
}
void del(rg int da,rg int val,rg int bit){
if(bit>20){
num[da]--;
return;
}
if(val&(1<<(bit-1))) del(ch[da][1],val,bit+1);
else del(ch[da][0],val,bit+1);
push_up(da,bit);
}
void xg(rg int da,rg int bit){
if(bit>20) return;
std::swap(ch[da][0],ch[da][1]);
if(ch[da][0]) xg(ch[da][0],bit+1);
push_up(da,bit);
}
int getans(rg int now){
rg int nans=0;
if(fa[now]) nans^=(a[fa[now]]+tag[fa[fa[now]]]);
nans^=sum[rt[now]];
return nans;
}
int main(){
memset(h,-1,sizeof(h));
read(n),read(m);
rg int aa,bb;
for(rg int i=1;i<n;i++){
read(aa),read(bb);
ad(aa,bb),ad(bb,aa);
}
dfs(1,0);
for(rg int i=1;i<=n;i++) if(fa[i]) insert(rt[fa[i]],0,1);
rg int nans=0;
for(rg int i=1;i<=m;i++){
read(aa);
tag[aa]++;
if(fa[aa]){
if(fa[fa[aa]]) del(rt[fa[fa[aa]]],a[fa[aa]]+tag[fa[fa[aa]]],1);
a[fa[aa]]++;
if(fa[fa[aa]]) insert(rt[fa[fa[aa]]],a[fa[aa]]+tag[fa[fa[aa]]],1);
}
xg(rt[aa],1);
nans=getans(aa);
ans=addmod(ans,mulmod(nans,addmod(mulmod(i,i),i)));
}
printf("%d
",ans);
return 0;
}
C. 多项式
分析
首先把题目中给的公式写出来,这些公式推导的时候会用到。
(x^{underline{n}}=sum_{k=0}^n(-1)^{n-k}s(n,k)x^k)
(x^n=sum_{k=0}^nS(n,k)x^{underline{k}})
(Delta^n f(x) sum_{i=0}^n(-1)^{n-i}inom{n}{i}f(x+i))
(Delta^n f(x) sum_{i=0}^dc_iinom{x}{n-i},f(x)=sum_{i=0}^dc_iinom{x}{i})
考虑二项式反演,设 (g[k]) 为钦定前 (n) 个变量中有 (k) 个变量 (>t) 的方案数。
那么 (g[k]=inom{n}{k}inom{s-kt}{m}),
含义就是从前面的 (n) 个位置中选出 (k) 个不合法的,那么还剩下 (s-kt) 个数分给 (m) 个位置,每一个位置上不能为空,数可以不放完。
用插板法,新加入一个集合存放多余的元素,再新加一个元素分给这个集合。
根据二项式反演,
(ans=sum_{i=0}^n(-1)^iinom{n}{i}inom{s-it}{m})
令 (i=n-i),则
(ans=sum_{i=0}^n(-1)^{n-i}inom{n}{i}inom{s-nt+it}{m})
设 (f(x)=inom{s-nt+xt}{m})
那么根据题目中的第三个式子
(Delta^n f(x)=sum_{i=0}^n(-1)^{n-i} inom{n}{i}inom{m}{s-nt+xt+it})
同时根据第四个式子,
(Delta^n f(0)=sum_{i=0}^mc_iinom{i-n}{0})
注意到只有 (inom{0}{0}) 才有值,所以 (Delta^n f(0)=c_n)。
所以只要求出 (c_n) 的值即可。
根据最后一个式子,(f(x)=sum_{i=0}^mc_iinom{x}{i})
暴力展开 (f(x)=sum_{i=0}^mc_i frac{x^{underline{i}}}{i!})
仍然使用题目中的良心公式,
(f(x)=sum_{i=0}^mfrac{c_i}{i!} sum_{j=0}^i(-1)^{i-j}s(i,j)x^j)
同时根据我们最开始的定义式,
(f(x)=inom{s-nt+xt}{m}=frac{1}{m!}(s-nt+xt)^{underline{m}}=frac{1}{m!}sum_{i=0}^m(-1)^{m-i}s(m,i)(s-nt+xt)^i)
对于任意 (x^k) 项,这两个式子的系数都是相同的
所以
(sum_{i=k}^mfrac{c_i}{i!}(-1)^{i-k}s(i,k)x^k=frac{1}{m!}sum_{i=k}^m(-1)^{m-i}s(m,i)inom{i}{k}t^k(s-nt)^{i-k}x^k)
对于这个式子可以依次求出 (c_m) 到 (c_n) 的值,然后回代
对于两个阶乘,可以把 (frac{1}{m!}) 乘到右边,因为 (m-i) 不会很大,所以可以直接算
对于组合数,可以预处理出一列,然后去递推
对于第一类斯特林数,我们会发现 (n-m) 很小,也就是说有很多个环的大小都为 (1),我们可以去枚举有哪些环的大小大于 (1)
那么就是 (sum_{i=0}^{n-m}inom{n}{m-i}ss(n-m+i,i))
其中 (ss(n,m)) 表示将 (n) 个元素排成 (m) 个环,环的大小至少为 (2) 的方案数
递推式为 (ss(n,m)=(n-1)ss(n-1,m)+(n-1)ss(n-2,m-1))。
实现的时候要精细一下。
代码
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
#define rg register
template<typename T>void read(rg T& x){
x=0;rg int fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
x*=fh;
}
const int maxn=2e3+5,mod=1000109107;
inline int addmod(rg int now1,rg int now2){
return now1+=now2,now1>=mod?now1-mod:now1;
}
inline int delmod(rg int now1,rg int now2){
return now1-=now2,now1<0?now1+mod:now1;
}
inline int mulmod(rg long long now1,rg int now2){
return now1*=now2,now1>=mod?now1%mod:now1;
}
int ksm(rg int ds,rg int zs){
rg int nans=1;
while(zs){
if(zs&1) nans=mulmod(nans,ds);
ds=mulmod(ds,ds);
zs>>=1;
}
return nans;
}
int n,m,t,ans,c[maxn][maxn],prestr[maxn][maxn],str[maxn][maxn],jc[maxn],jcc[maxn],ny[maxn],beg;
long long s;
int getC(rg int nn,rg int mm){
if(nn<mm || nn<0 || mm<0) return 0;
return c[nn-beg][mm-beg];
}
int getpres(rg int nn,rg int mm){
rg int nans=0;
for(rg int i=0;i<=nn-mm;i++){
nans=addmod(nans,mulmod(getC(nn,mm-i),prestr[nn-mm+i][i]));
}
return nans;
}
int getS(rg int nn,rg int mm){
return str[nn-n][mm-n];
}
void pre(){
ny[1]=1;
for(rg int i=2;i<maxn;i++) ny[i]=mulmod(mod-mod/i,ny[mod%i]);
jc[0]=jcc[0]=1;
for(rg int i=1;i<maxn;i++){
jc[i]=mulmod(jc[i-1],i);
jcc[i]=mulmod(jcc[i-1],ny[i]);
}
beg=std::max(0,n-1000);
c[0][0]=1;
for(rg int i=1;i<maxn;i++){
c[i][0]=mulmod(c[i-1][0],mulmod(beg+i,ny[i]));
}
for(rg int i=1;i<maxn;i++){
for(rg int j=1;j<=i;j++){
c[i][j]=addmod(c[i-1][j],c[i-1][j-1]);
}
}
prestr[0][0]=1;
for(rg int i=2;i<maxn;i++){
for(rg int j=1;j<=i;j++){
prestr[i][j]=addmod(mulmod(i-1,prestr[i-2][j-1]),mulmod(i-1,prestr[i-1][j]));
}
}
str[0][0]=getpres(n,n);
for(rg int i=1;i<=m-n;i++){
str[i][0]=getpres(n+i,n);
}
for(rg int i=1;i<=m-n;i++){
for(rg int j=1;j<=i;j++){
str[i][j]=addmod(str[i-1][j-1],mulmod(i+n-1,str[i-1][j]));
}
}
}
int xs[maxn];
void solve(){
rg int tmp;
for(rg int i=m;i>=n;i--){
tmp=1;
for(rg int j=m;j>=i+1;j--){
xs[i-n]=delmod(xs[i-n],mulmod(xs[j-n],mulmod(tmp,mulmod(getS(j,i),ksm(mod-1,j-i)))));
tmp=mulmod(tmp,j);
}
for(rg int j=i;j<=m;j++){
xs[i-n]=addmod(xs[i-n],mulmod(ksm(mod-1,m-j),mulmod(getS(m,j),mulmod(getC(j,i),mulmod(ksm(t,i),ksm((s-1LL*n*t)%mod,j-i))))));
}
tmp=1;
for(rg int j=i+1;j<=m;j++) tmp=mulmod(tmp,ksm(j,mod-2));
xs[i-n]=mulmod(xs[i-n],tmp);
}
}
int main(){
read(s),read(t),read(n),read(m);
pre();
solve();
printf("%d
",xs[0]);
return 0;
}