3.13 模拟赛

T1 words

题目大意: bzoj 4567

题解链接

考试代码:

(如果不重建树的话会出锅 例子:

其中加粗的边为有$end$标记的节点,若不重建树,则左边$a$的$sz$为4,右边为3会先走右边

实际上应该先走左边(man太惨了。

View Code

 

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$修改即可非常完美的解决

  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 }
View Code

 

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$

 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 }
View Code

前置知识:范德蒙德卷积即$\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$的逆元

 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 }
View Code

 

posted @ 2019-03-14 09:14  jack_yyc  阅读(228)  评论(0编辑  收藏  举报