bzoj [ 2017省队十连测推广赛1 ] ( 4765 && 4766 && 4767 )题解

来源:互联网 发布:淘宝购买家具退货 编辑:程序博客网 时间:2024/06/03 20:45
bzoj 4765 -- 分块+dfs序+树状数组:

考虑分块。将1~n分成sqrt(n)块,对每个点记录它在每个块中的祖先个数,修改一个点时枚举每一块修改。

查询[l,r]时如果一个块在[l,r]中,直接将其加入答案。显然只剩下O(sqrt(n))个点。求出树的dfs序,用树状数组维护就可以O(logn)求出答案。

时间复杂度O(n*sqrt(n)*logn)

代码:

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 inline char nc(){ 7     static char buf[100000],*p1=buf,*p2=buf; 8     if(p1==p2){ 9         p2=(p1=buf)+fread(buf,1,100000,stdin);10         if(p1==p2)return EOF;11     }12     return *p1++;13 }14 inline void Read(int& x){15     char c=nc();16     for(;c<'0'||c>'9';c=nc());17     for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());18 }19 #define ULL unsigned long long20 #define ll long long21 #define N 10001022 #define SN 40023 #define lowbit(x) x&-x24 struct Edge{25     int t,nx;26 }e[N<<1];27 ULL Sum[SN],c[N],p[N];28 ll k;29 int i,j,n,m,Cnt,s[N][SN],t[SN],S,T,a[N],b[N],f[N],h[N],B[N],Num,Rt,x,y,z;30 inline void Add(int x,int y){31     e[++Num].t=y;e[Num].nx=h[x];h[x]=Num;32 }33 inline void Update_c(int x,int y){34     for(;x<=n;x+=lowbit(x))c[x]+=y;35 }36 inline void Dfs(int x,int F){37     p[x]=a[x];b[x]=++m;if(a[x])Update_c(b[x],a[x]);t[B[x]]++;38     for(int i=1;i<=Cnt;i++)s[x][i]=t[i];39     for(int i=h[x];i;i=e[i].nx)40     if(e[i].t!=F){41         Dfs(e[i].t,x);42         p[x]+=p[e[i].t];43     }44     Sum[B[x]]+=p[x];f[x]=m;t[B[x]]--;45 }46 inline void Update(int x,int y){47     for(int i=1;i<=Cnt;i++)Sum[i]+=1ll*y*s[x][i];48     Update_c(b[x],y);49 }50 inline ULL Query_c(int l,int r){51     ULL Ans=0;52     for(int i=r;i;i-=lowbit(i))Ans+=c[i];53     for(int i=l-1;i;i-=lowbit(i))Ans-=c[i];54     return Ans;55 }56 inline ULL Query(int l,int r){57     ULL Ans=0;58     if(B[l]==B[r]){59         for(int i=l;i<=r;i++)Ans+=Query_c(b[i],f[i]);60         return Ans;61     }62     for(int i=B[l]+1;i<B[r];i++)Ans+=Sum[i];63     for(int i=l;B[i]==B[l];i++)Ans+=Query_c(b[i],f[i]);64     for(int i=r;B[i]==B[r];i--)Ans+=Query_c(b[i],f[i]);65     return Ans;66 }67 char ss[40];68 int Len;69 inline void Print(ULL x){70     if(x==0)putchar(48);71     for(Len=0;x;x/=10)ss[++Len]=x%10;72     for(;Len;)putchar(ss[Len--]+48);putchar('\n');73 }74 int main()75 {76     Read(n);Read(T);S=sqrt((double)n);77     for(i=1;i<=n;i++)B[i]=(i-1)/S+1;Cnt=B[n];78     for(i=1;i<=n;i++)Read(a[i]);79     for(i=1;i<=n;i++){80         Read(x);Read(y);81         if(x==0)Rt=y;else Add(x,y),Add(y,x);82     }83     Dfs(Rt,0);84     while(T--){85         Read(z);Read(x);Read(y);86         if(z&1)Update(x,y-a[x]),a[x]=y;else Print(Query(x,y));87     }88     return 0;89 }
bzoj4765


bzoj 4766 -- 快速幂+快速乘

一个结论:

一个完全二分图的生成树个数为nm-1*mn-1

由于要爆long long,要用快速乘。

代码:

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define ll long long 6 ll n,m,p,a,b; 7 inline ll Ch(ll x,ll y){ 8     ll Ans=0; 9     while(y){10         if(y&1)Ans=(Ans+x)%p;11         x=(x<<1)%p;12         y>>=1;13     }14     return Ans;15 }16 inline ll Pow(ll x,ll y){17     if(y==0)return 1;18     ll Ans=Pow(x,y>>1);19     if(y&1)return Ch(Ch(Ans,Ans),x);20     return Ch(Ans,Ans);21 }22 int main()23 {24     scanf("%lld%lld%lld",&n,&m,&p);25     a=Pow(n,m-1);b=Pow(m,n-1);26     printf("%lld",Ch(a,b));27 }
bzoj4766


bzoj4767 -- DP+容斥

对于每个障碍点,从原点到它要使用的两种操作的次数可以用解方程解出。

对于一个障碍点,假如它需要的操作次数分别是x,y,那么从原点到它的路径种数就是(x+y)!/(x!*y!)

将每个障碍点需要的两种操作次数作为坐标。

对障碍点按x排序一遍,令f[i]表示从原点到i号障碍点不经过任何障碍点的路径种数,那么得到DP方程:

f[i]=g(x[i],y[i])-Σf[j]*g(x[i]-x[j],y[i]-y[j]),j<i且y[j]<y[i]

其中g(i,j)表示从原点到(i,j)的方案数。

预处理出阶乘、逆元的阶乘就可以了。

时间复杂度O(n*logn)

代码:

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define N 510 7 #define Max 1000000 8 #define M 1000000007 9 struct Node{10     int x,y;11 }a[N],A,B;12 int i,j,k,n,m,x,y,f[N],J1[Max],J2[Max],Ni[Max],X,Y;13 inline void Solve(int x,int y){14     int a1=B.x*y-x*B.y,a2=A.y*B.x-A.x*B.y;15     if(a1%a2)return;16     int Ax=a1/a2;17     a1=A.x*y-A.y*x,a2=A.x*B.y-A.y*B.x;18     if(a1%a2)return;19     int Ay=a1/a2;20     if(Ax<0||Ay<0)return;21     if(i<Max&&(Ax>a[1].x||Ay>a[1].y))return;22     a[++m].x=Ax;a[m].y=Ay;23 }24 inline bool Cmp(Node a,Node b){25     return a.x<b.x||(a.x==b.x&&a.y<b.y);26 }27 inline int Work(int x,int y){28     return (1ll*J1[x+y]*J2[x])%M*J2[y]%M;29 }30 int main()31 {32     scanf("%d%d%d%d%d%d%d",&X,&Y,&n,&A.x,&A.y,&B.x,&B.y);33     for(J1[1]=J2[1]=Ni[1]=J1[0]=J2[0]=1,i=2;i<Max;i++)J1[i]=1ll*J1[i-1]*i%M,Ni[i]=1ll*(M-M/i)*Ni[M%i]%M,J2[i]=1ll*J2[i-1]*Ni[i]%M;34     Solve(X,Y);35     if(m==0){printf("0");return 0;}36     for(i=1;i<=n;i++){37         scanf("%d%d",&x,&y);Solve(x,y);38         if(x==X&&y==Y){printf("0");return 0;}39     }40     sort(a+1,a+m+1,Cmp);41     for(i=1;i<=m;i++){42         f[i]=Work(a[i].x,a[i].y);43         for(j=1;j<i;j++)if(a[j].y<=a[i].y)f[i]=(f[i]-1ll*f[j]*Work(a[i].x-a[j].x,a[i].y-a[j].y)%M)%M;44     }45     printf("%d",(f[m]+M)%M);46     return 0;47 }
bzoj4767


原创粉丝点击