zoukankan      html  css  js  c++  java
  • 省选测试41

    省选测试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;
    }
    
  • 相关阅读:
    QOMO Linux 4.0 正式版发布
    LinkChecker 8.1 发布,网页链接检查
    pgBadger 2.1 发布,PG 日志分析
    Aletheia 0.1.1 发布,HTTP 调试工具
    Teiid 8.2 Beta1 发布,数据虚拟化系统
    zLogFabric 2.2 发布,集中式日志存储系统
    开源电子工作套件 Arduino Start Kit 登场
    Piwik 1.9 发布,网站访问统计系统
    Ruby 1.9.3p286 发布,安全修复版本
    toBraille 1.1.2 发布,Java 盲文库
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14578918.html
Copyright © 2011-2022 走看看