3.13 模拟赛
T1 words
题目大意: bzoj 4567
考试代码:
(如果不重建树的话会出锅 例子:
其中加粗的边为有$end$标记的节点,若不重建树,则左边$a$的$sz$为4,右边为3会先走右边
实际上应该先走左边(man太惨了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
T2 tree
题目大意:bzoj 4817
一棵树 支持三种操作:
1 x:把点x到根节点的路径上所有的点染上一种没有用过的新颜色
2 x y:求x到y的路径的权值
3 x:在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值
思路:
(之前看wls做过这道题,对大致思路有一个了解,当时感觉好神啊
维护每个点到根的路径的权值
这样两个询问的答案分别为$val_a+val_b-2*val_{lca}+1$与子树中的最大值,用线段树可以很方便的维护
对于修改,发现这个过程与$LCT$的$access$很像
使用$LCT$来维护修改,即对于修改,$access$该点,并在过程中修改
找到两个部分内最浅的点,然后用线段树一个$+1$一个$-1$修改即可非常完美的解决
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<set> 10 #include<map> 11 #define ll long long 12 #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i) 13 #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i) 14 #define ren for(int i=fst[x];i;i=nxt[i]) 15 #define MAXN 100100 16 using namespace std; 17 inline int read() 18 { 19 int x=0,f=1;char ch=getchar(); 20 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 21 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 22 return x*f; 23 } 24 int n,m,fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],cnt,dep[MAXN]; 25 int fa[MAXN],sz[MAXN],hvs[MAXN],tot,bl[MAXN],in[MAXN]; 26 int mx[MAXN<<2],tag[MAXN<<2]; 27 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;} 28 void dfs(int x,int pa) 29 { 30 fa[x]=pa,sz[x]=1; 31 ren if(to[i]^pa) dep[to[i]]=dep[x]+1,dfs(to[i],x), 32 sz[x]+=sz[to[i]],hvs[x]=sz[to[i]]>sz[hvs[x]]?to[i]:hvs[x]; 33 } 34 void Dfs(int x,int anc) 35 { 36 bl[x]=anc,in[x]=++tot;if(!hvs[x]) return ; 37 Dfs(hvs[x],anc);ren if(to[i]^fa[x]&&to[i]^hvs[x]) Dfs(to[i],to[i]); 38 } 39 int lca(int a,int b) 40 { 41 for(;bl[a]!=bl[b];a=fa[bl[a]]) 42 if(dep[bl[a]]<dep[bl[b]]) swap(a,b); 43 return in[a]<in[b]?a:b; 44 } 45 void pshd(int k) 46 { 47 mx[k<<1]+=tag[k],mx[k<<1|1]+=tag[k]; 48 tag[k<<1]+=tag[k],tag[k<<1|1]+=tag[k],tag[k]=0; 49 } 50 void mdf(int k,int l,int r,int a,int b,int x) 51 { 52 if(l==a&&r==b) {tag[k]+=x,mx[k]+=x;return ;}int mid=l+r>>1; 53 if(tag[k]) pshd(k); 54 if(b<=mid) mdf(k<<1,l,mid,a,b,x); 55 else if(a>mid) mdf(k<<1|1,mid+1,r,a,b,x); 56 else {mdf(k<<1,l,mid,a,mid,x);mdf(k<<1|1,mid+1,r,mid+1,b,x);} 57 mx[k]=max(mx[k<<1],mx[k<<1|1]); 58 } 59 int query(int k,int l,int r,int a,int b) 60 { 61 if(l==a&&r==b) return mx[k];int mid=l+r>>1; 62 if(tag[k]) pshd(k); 63 if(b<=mid) return query(k<<1,l,mid,a,b); 64 else if(a>mid) return query(k<<1|1,mid+1,r,a,b); 65 else return max(query(k<<1,l,mid,a,mid),query(k<<1|1,mid+1,r,mid+1,b)); 66 } 67 namespace lct 68 { 69 int ch[MAXN][2],tag[MAXN],fa[MAXN]; 70 int which(int x) {return ch[fa[x]][1]==x;} 71 int isroot(int x) {return ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x;} 72 void rotate(int x) 73 { 74 int f=fa[x],ff=fa[f],k=which(x); 75 if(!isroot(f)) ch[ff][ch[ff][1]==f]=x;fa[x]=ff; 76 ch[f][k]=ch[x][k^1],fa[ch[x][k^1]]=f,ch[x][k^1]=f,fa[f]=x; 77 } 78 void splay(int x) 79 { 80 for(int f;!isroot(x);rotate(x)) 81 if(!isroot(f=fa[x])) rotate(which(x)==which(f)?f:x); 82 } 83 int find(int x) {while(ch[x][0]) x=ch[x][0];return x;} 84 void access(int x) 85 { 86 for(int t=0,tmp;x;t=x,x=fa[x]) 87 { 88 splay(x); 89 if(ch[x][1]){tmp=find(ch[x][1]);mdf(1,1,n,in[tmp],in[tmp]+sz[tmp]-1,1);} 90 ch[x][1]=t;if(t){tmp=find(t);mdf(1,1,n,in[tmp],in[tmp]+sz[tmp]-1,-1);} 91 } 92 } 93 }; 94 int main() 95 { 96 n=read(),m=read();int a,b,c;rep(i,2,n) a=read(),b=read(),add(a,b),add(b,a); 97 dep[1]=1;dfs(1,0);Dfs(1,1);rep(i,1,n) mdf(1,1,n,in[i],in[i],dep[i]),lct::fa[i]=fa[i]; 98 while(m--) 99 { 100 c=read(),a=read(); 101 if(c==1) lct::access(a); 102 else if(c==2) 103 { 104 b=read(),c=lca(a,b); 105 printf("%d\n",query(1,1,n,in[a],in[a])+query(1,1,n,in[b],in[b])-2*query(1,1,n,in[c],in[c])+1); 106 } 107 else printf("%d\n",query(1,1,n,in[a],in[a]+sz[a]-1)); 108 } 109 }
T3 coin
题目大意:bzoj 4830
两个人分别抛$a$次和$b$次硬币,$a \geq b$
求扔$a$次正面总数大于$b$次正面总数的总方案数
思路:
考试时候得了30分 即$\sum\limits_{i=1}^a \sum\limits_{j=1}^{min(j,b-1)} C_a^i * C_b^j$
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<set> 10 #include<map> 11 #define ll long long 12 #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i) 13 #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i) 14 #define ren for(int i=fst[x];i;i=nxt[i]) 15 #define MAXN 600100 16 int MOD; 17 #define pls(a,b) (a+b)%MOD 18 #define mul(a,b) ((1LL*a)%MOD*b)%MOD 19 using namespace std; 20 inline int read() 21 { 22 int x=0,f=1;char ch=getchar(); 23 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 24 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 25 return x*f; 26 } 27 int n,m,k; 28 struct P30 29 { 30 int c[1100][1100],ans,t1; 31 P30(){memset(c,0,sizeof(c));ans=t1=0;} 32 void pre() 33 { 34 c[0][0]=1; 35 rep(i,1,n) {c[i][0]=1;rep(j,1,i) c[i][j]=pls(c[i-1][j],c[i-1][j-1]);} 36 } 37 void work() 38 { 39 MOD=(int)pow(10,k);pre();ans=t1=0; 40 rep(i,1,n) t1=pls(c[m][i-1],t1),ans=pls(mul(t1,c[n][i]),ans); 41 if(k==1) printf("%01d\n",ans); 42 if(k==2) printf("%02d\n",ans); 43 if(k==3) printf("%03d\n",ans); 44 if(k==4) printf("%04d\n",ans); 45 if(k==5) printf("%05d\n",ans); 46 if(k==6) printf("%06d\n",ans); 47 if(k==7) printf("%07d\n",ans); 48 if(k==8) printf("%08d\n",ans); 49 if(k==9) printf("%09d\n",ans); 50 } 51 }p30; 52 int main() 53 { 54 while(scanf("%d",&n)!=EOF) 55 { 56 m=read(),k=read(); 57 if(max(n,m)<=1000) p30.work(); 58 } 59 }
前置知识:范德蒙德卷积即$\sum\limits_{i=0}^k C_n^i * C_m^{k-i} =C_{n+m}^k$,可以通过其意义简单证明
首先考虑$a=b$的情况,发现对于两人得分不同的情况,将整个序列取反后胜负情况都会发生变化
那么答案即为全集减去得分相同的情况再除以二即$\frac{2^{2a}-C_{2a}^a}{2}$
对于$a>b$的情况 发现会存在取反之后A的得分依然高于B的情况,设B原本得分为$i$,A比B多得分为$j$
其余情况仍然满足原来B赢的情况取反后为A赢
对于特殊情况 则有$a-i-j>b-i$即$j<a-b$ 与题目中$a-b \leq 10000$的条件符合
设$S$表示特殊情况 则答案为$\frac{2^{2a}+S}{2}$
$$S=\sum\limits_{i=0}^b \sum\limits_j^{a-b-1} C_b^i C_a^{i+j}=\sum\limits_{i=0}^b \sum\limits_j^{a-b-1} C_b^{b-i} C_a^{i+j}=\sum\limits_{i=0}^{a-b-1} C_{a+b}^{b+i}$$
然后就可以使用拓展$lucas$来求解了
但此题卡常 有很多东西需要注意:
由于只有两个质因数,可以预处理阶乘;以及组合数只需要求一半
除以2的东西需要讨论,对$2^k$少乘一个$2$,对$5^k$乘以个$2$的逆元
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 2001000 15 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 16 #define lrep(i,s,t) for(register ll i=(s),i##__end=(t);i<=i##__end;++i) 17 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 18 #define ren for(register int i=fst[x];i;i=nxt[i]) 19 #define pb(i,x) vec[i].push_back(x) 20 #define pls(a,b) (a+b)%MOD 21 #define mns(a,b) (a-b+MOD)%MOD 22 #define mul(a,b) (1LL*(a)*(b))%MOD 23 using namespace std; 24 inline ll read() 25 { 26 ll x=0,f=1;char ch=getchar(); 27 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 28 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 29 return x*f; 30 } 31 ll T,n,m,MOD,p2,p5,pw[MAXN][2];int K; 32 ll q_pow(ll a,ll t,ll p,ll res=1) 33 { 34 for(a%=p;t;t>>=1,(a*=a)%=p) 35 if(t&1) (res*=a)%=p;return res; 36 } 37 ll exgcd(ll a,ll b,ll &x,ll &y) 38 { 39 if(!b){x=1,y=0;return a;} 40 ll d=exgcd(b,a%b,y,x);y-=(a/b)*x;return d; 41 } 42 ll Pw(ll n,ll p,ll pk) 43 { 44 if(!n) return 1;ll res=1; 45 res=q_pow(pw[pk][p==5],n/pk,pk); 46 (res*=pw[n%pk][p==5])%=MOD; 47 return (res*Pw(n/p,p,pk))%pk; 48 } 49 ll inv(ll n,ll p) {ll x,y;exgcd(n,p,x,y);return (x+p)%p;} 50 ll C(ll n,ll m,ll p,ll pk,int f) 51 { 52 ll sum=0;for(ll i=n;i;i/=p) sum+=i/p;for(ll i=m;i;i/=p) sum-=i/p; 53 for(ll i=n-m;i;i/=p) sum-=i/p; 54 if(p==2&&f) sum--;if(sum>K) return 0; 55 ll pn=Pw(n,p,pk),pm=Pw(m,p,pk),pz=Pw(n-m,p,pk); 56 ll tmp=1;if(p==5&&f) tmp=inv(2,pk); 57 pm=inv(pm,pk),pz=inv(pz,pk); 58 return ((((q_pow(p,sum,pk)*pn)%MOD*pm)%MOD*pz)%MOD*tmp)%MOD; 59 } 60 ll exlucas(ll n,ll m,ll p,int f) 61 { 62 return ((C(n,m,2,p2,f)*inv(p5,p2)%MOD*p5)%MOD+(C(n,m,5,p5,f)*inv(p2,p5)%MOD*p2)%MOD)%MOD; 63 } 64 void Print(ll a,int k) 65 { 66 if(k==1) printf("%01lld\n",a); 67 if(k==2) printf("%02lld\n",a); 68 if(k==3) printf("%03lld\n",a); 69 if(k==4) printf("%04lld\n",a); 70 if(k==5) printf("%05lld\n",a); 71 if(k==6) printf("%06lld\n",a); 72 if(k==7) printf("%07lld\n",a); 73 if(k==8) printf("%08lld\n",a); 74 if(k==9) printf("%09lld\n",a); 75 } 76 void work(ll n,ll m,int k,ll ans=0) 77 { 78 p2=q_pow(2,k,inf),p5=q_pow(5,k,inf),MOD=p2*p5; 79 if(n==m) ans=(q_pow(2,(n<<1)-1,MOD)-exlucas(n<<1,n,MOD,1)+MOD)%MOD; 80 else 81 { 82 ans=q_pow(2,n+m-1,MOD); 83 lrep(i,((n+m)>>1)+1,n-1) (ans+=exlucas(n+m,i,MOD,0))%=MOD; 84 if(!((n+m)&1)) (ans+=exlucas(n+m,(n+m)>>1,MOD,1))%=MOD; 85 } 86 Print(ans,k); 87 } 88 int main() 89 { 90 pw[0][0]=pw[0][1]=1; 91 rep(i,1,512) if(i%2) pw[i][0]=(pw[i-1][0]*i)%512;else pw[i][0]=pw[i-1][0]; 92 rep(i,1,1953125) if(i%5) pw[i][1]=(pw[i-1][1]*i)%1953125;else pw[i][1]=pw[i-1][1]; 93 while(~scanf("%lld%lld%d",&n,&m,&K)) {work(n,m,K);} 94 }