7.27题解

T1

什么原根,矩阵乘,循环矩阵,还有什么倍增优化DP各种乱搞,说实话我没几个会的,打个暴力DP吧,还一直RE0,快自闭了,如果有缘,等我过掉他再填坑吧

T2

考思维和手推式子的好题啊,看的就是谁能发现一些别人发现不了的式子,当然了,我一个也没发现,建议自己拿张纸写一写,纯看别人题解真的看不懂

40分

emm,我考场上想出来的暴力,对于t=0倍增LCA求两点之间的距离,直接带入求b,可过第一个点,t=1最简单的办法就是高斯消元可过2,3,4,前提是高斯消元记得打对了,卡精度啊!!!

50分

多的那10分是针对一条链的,要开始推式子咯

t=0时,我们换个思路,由之前计算点的贡献,改为计算边的贡献,以中间点3为例,3左侧的边对于b[3]的贡献是每条边左侧点的a值之和,其实还算好想,可以自己画个样例,列一下原题的式子,拆一下合一下就可以发现它很显然了,分一下左右两侧,设qian[i]=a[1]+a[2]+...+a[i],hou[i]=a[i]+a[i+1]+...+a[n],也就是一个前缀一个后缀,那我们就可以得到b[i]=qian[1]+qian[2]+...+qian[i-1]+hou[i+1]+hou[i+2]+...+hou[n],分别对前缀求前缀和,后缀求后缀和就可以O(n)得到了b数组了

t=1时显然依旧用刚才的式子

b[1]=hou[2]+hou[3]+...+hou[n]  b[2]=qian[1]+hou[3]+hou[4]+...+hou[n]  b[3]=qian[1]+qian[2]+hou[4]+hou[5]+...+hou[n]  b[4]=qian[1]+...+qian[3]+hou[5]+hou[6]+...+hou[n]

有好多相同的项啊,手不痒吗?不想消项吗,动手吧

b[2]-b[1]=qian[1]-hou[2]  b[3]-b[2]=qian[2]-hou[3]

b[4]-b[3]=qian[3]-hou[4]  ......  b[n]-b[n-1]=qian[n-1]-hou[n]

qian,hou数组之间有什么关系呢?显然设SUM=a[1]+a[2]+a[3]+...+a[n],那么就有

qian[i-1]+hou[i]=SUM,qian[i-1]=SUM-hou[i],带入又得到了一串式子

b[2]-b[1]=SUM-2*hou[2]  b[3]-b[4]=SUM-2*hou[3]

b[4]-b[3]=SUM-2*hou[4]  ......  b[n]-b[n-1]=SUM-2*hou[n]

有因为我们有b[1]=hou[2]+hou[3]+...+hou[n],有没有想到什么?把刚才的n-1个式子加起来,就可以凑出两个b[1]了啊,好东西,n-1个式子做和然后消项会得到b[n]-b[1]=(n-1)SUM-2*b[1],再一下项,就可以得到SUM=(b[1]+b[n])/(n-1),把SUM带回刚才的n-1个式子,可以求得出了hou[1]之外的完整hou数组,那把求后缀和倒过来

hou[i]=(SUM-b[i]+b[i-1])/2

就可以求得除了a[1]之外的a数组,那a[1]怎么办呢,我们回到b[2]-b[1]=qian[1]-hou[2],现在式子中只剩一个未知量qian[1],诶,qian[1]不就是a[1]嘛,这不就搞定了

虽然我们推了这么一大片只有十分,但它对正解的贡献还是非常大滴

100分

正解来咯

t=0时,我们依旧用最初的暴力,通过一遍DFS跑一下LCA,求出b[1],其实LCA很没劲,点i对b[1]的贡献就是a[i]*(deep[i]-1),不需要LCA,O(n)扫一下就好了,知道了b[1]的话,我们可以找一找他的儿子们的b值和他的之间有没有什么关系,如图

b[1]=a[1]*0+a[2]*1+a[3]*1+a[4]*1+a[5]*2+a[6]*2+a[7]*2+a[8]*2

b[2]=a[1]*1+a[2]*0+a[3]*2+a[4]*2+a[5]*1+a[6]*1+a[7]*3+a[8]*3

一一对应一下,发现了什么?2为根的子树中的点对2的贡献都少了一,其余点的贡献都多了一,当然多一少一都是对于有父子关系的点来说的,我们用size[i]代表以i为根的子树中的a值之和,在刚才的DFS中可以顺便求出,那么b[2]=b[1]-size[2]+(size[1]-size[2])=b[1]+size[1]-2*size[2],我们推广到所有有父子关系的点

b[son]=b[fa]+size[1]-2*size[son]

这样的话再跑一遍dfs就可以求得所有的b了

t=1,想想有没有些和b有关的式子,当然啦,刚才写的那个不就是嘛,依旧移项,可以得到b[son]-b[fa]=size[1]-2*size[son],设c[i]=size[1]-2*size[i],我们就可以求得除了c[1]之外的整个c数组

现在我们继续思考,b[1]=?,我们想啊,一个深度为deep的点,肯定是有deep-1个父节点,那么他就被包含进了除以1为根之外的deep-1个子树中(自己作为根也是一个子树),而恰好一个点对于b[1]的贡献就是a[i]*(deep[i]-1),所以

b[1]=size[2]+size[3]+size[4]+...+size[n]

有没有觉得c数组和他有些联系?我们给除c[1]之外的整个c数组加和,tot=(n-1)size[1]-2*(size[2]+size[3]+...+size[n]),眼熟吧,tot=(n-1)size[1]-2*b[1],那就可以得到

size[1]=(tot+2*b[1])/(n-1)

那么同时你就会发现其他点的size也变得可求了

size[i]=(size[1]-c[i])/2

那再跑一遍dfs把用a求size的式子倒过来,就可以求得所有的a了,当然a[1]这次就不特殊了,一起就求出来了

这道题怎么说呢,思维量稍大,考思维的同时,部分分还考了板子,比较全面了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #define int long long
 6 #define maxn 100100
 7 #define maxnnn 1100
 8 #define maxk 19
 9 using namespace std;
10 int t,fl,n,js;
11 int yz[maxn],qiu[maxn];
12 int head[maxn],to[maxn*2],xia[maxn*2];
13 int fa[maxn],deep[maxn],size[maxn],c[maxn];
14 void clear()
15 {
16     js=0;
17     memset(yz,0,sizeof(yz));  memset(qiu,0,sizeof(qiu));
18     memset(head,0,sizeof(head));  memset(to,0,sizeof(to));
19     memset(xia,0,sizeof(xia));  memset(fa,0,sizeof(fa));
20     memset(deep,0,sizeof(deep));  memset(size,0,sizeof(size));
21     memset(c,0,sizeof(c));
22 }
23 void add(int x,int y)
24 {
25     to[++js]=y;  xia[js]=head[x];  head[x]=js;
26 }
27 void dfs(int x)
28 {
29     size[x]=yz[x];
30     for(int i=head[x];i;i=xia[i])
31     {
32         int ls=to[i];
33         if(deep[ls]==0)
34         {
35             deep[ls]=deep[x]+1;  fa[ls]=x;
36             dfs(ls);  size[x]+=size[ls];
37         }
38     }
39 }
40 void Dfs(int x)
41 {
42     for(int i=head[x];i;i=xia[i])
43     {
44         int ls=to[i];
45         if(fa[ls]==x)  {qiu[ls]=qiu[x]-2*size[ls]+size[1];  Dfs(ls);}
46     }
47 }
48 void DFs(int x)
49 {
50     for(int i=head[x];i;i=xia[i])
51     {
52         int ls=to[i];
53         if(fa[ls]==0)  {fa[ls]=x;  c[ls]=yz[ls]-yz[x];  DFs(ls);}
54     }
55 }
56 void DFS(int x)
57 {
58     for(int i=head[x];i;i=xia[i])
59     {
60         int ls=to[i];
61         if(fa[ls]==x)  {size[x]-=size[ls];  DFS(ls);}
62     }
63 }
64 signed main()
65 {
66     scanf("%lld",&t);
67     while(t--)
68     {
69         clear();  scanf("%lld",&n);
70         for(int i=1;i<n;++i)
71         {
72             int u,v;  scanf("%lld%lld",&u,&v);
73             add(u,v);  add(v,u);
74         }
75         scanf("%lld",&fl);
76         if(fl==0)
77         {
78             for(int i=1;i<=n;++i)  scanf("%lld",&yz[i]);
79             deep[1]=1;  dfs(1);
80             for(int i=2;i<=n;++i)  qiu[1]+=yz[i]*(deep[i]-deep[1]);
81             Dfs(1);
82             for(int i=1;i<=n;++i)  printf("%lld ",qiu[i]);
83             puts("");
84         }
85         else
86         {
87             for(int i=1;i<=n;++i)  scanf("%lld",&yz[i]);
88             fa[1]=-1;  DFs(1);
89             int sum=0;
90             for(int i=2;i<=n;++i)  sum+=c[i];
91             size[1]=(sum+2*yz[1])/(n-1);
92             for(int i=2;i<=n;++i)  size[i]=(size[1]-c[i])/2;
93             DFS(1);
94             for(int i=1;i<=n;++i)  {qiu[i]=size[i];  printf("%lld ",qiu[i]);}
95             puts("");
96         }
97     }
98     return 0;
99 }
全都是dfs

T3

相比之下这道纯数学题反而不太难了

opt=0和上次的T2visit一毛一样,式子直接抄,而且这次还友好的不需要CRT了,直接求阶乘和逆元就可以

opt=1这是个卡特兰数,我看出来了,很开心,因为只在一条轴的一半上走,向右看作入栈,向左看作出栈,就是卡特兰数的基础模型

opt=2考试推了半个小时也没推出式子来,且忘了可以先打表找规律之类的,最后暴力没打完,死了,考后题解没看懂,所以选择了DP解决,由于空间不允许,所以我选择了把一个三维数组,拆成了两个二维数组和一个一维数组,不过可能换个题就不可用了

opt=3这次是组合数+卡特兰,我们假设选i步在竖直方向上走,那首先就会出现一个C(n,i),然后由于有不超过原点的限制,所以还是进出栈模型,由于算是有两个方向,所以是两个卡特兰数相乘,最终结果为C(n,i)*cat(i/2)*cat((n-i)/2),看见/2没,记得保证偶数啊

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define ll long long
 5 #define maxn 100100
 6 #define maxx 1100
 7 using namespace std;
 8 const long long mod=1e9+7;
 9 int n,typ;
10 ll ans;
11 ll jc[maxn*2],ny[maxn*2],as[maxx];
12 ll ss[maxx][maxx*2],sp[maxx][maxx*2];
13 ll ksm(ll a,ll b,ll c)
14 {
15     ll ans=1;  a=a%c;
16     while(b)
17     {
18         if(b&1)  ans=(ans*a)%c;
19         b=b>>1;  a=(a*a)%c;
20     }
21     return ans%c;
22 }
23 void work1()
24 {
25     for(int u=0;u<=n/2;++u)
26     {
27         int l=n/2-u;
28         ans=(ans+(((((jc[n]*ny[u])%mod*ny[u])%mod)*ny[l]%mod)*ny[l])%mod)%mod;
29     }
30     printf("%lld\n",ans%mod);
31 }
32 void work2()
33 {
34     n=n/2;
35     ans=(((((jc[2*n]*ny[n])%mod*ny[n])%mod*jc[n])%mod)*ny[n+1])%mod;
36     printf("%lld\n",ans%mod);
37 }
38 void work3()
39 {
40     as[0]=1;
41     for(int o=1;o<=n;++o)
42     {
43         for(int i=0;i<=2*n;++i)
44         {
45             if(i==n)
46             {
47                 as[o]=(as[o]+ss[o-1][n-1])%mod;  as[o]=(as[o]+ss[o-1][n+1])%mod;
48                 as[o]=(as[o]+sp[o-1][n-1])%mod;  as[o]=(as[o]+ss[o-1][n+1])%mod;
49             }
50             else
51             {
52                 if(i-1!=n)
53                 {
54                     if(i-1>=0)
55                     {
56                         ss[o][i]=(ss[o][i]+ss[o-1][i-1])%mod;
57                         sp[o][i]=(sp[o][i]+sp[o-1][i-1])%mod;
58                     }
59                 }
60                 else  {ss[o][i]=(ss[o][i]+as[o-1])%mod;  sp[o][i]=(sp[o][i]+as[o-1])%mod;}
61                 if(i+1!=n)
62                 {
63                     ss[o][i]=(ss[o][i]+ss[o-1][i+1])%mod;
64                     sp[o][i]=(sp[o][i]+sp[o-1][i+1])%mod;
65                 }
66                 else  {ss[o][i]=(ss[o][i]+as[o-1])%mod;  sp[o][i]=(sp[o][i]+as[o-1])%mod;}
67             }
68         }
69     }
70     printf("%lld\n",as[n]%mod);
71 }
72 void work4()
73 {
74     for(int i=0;i<=n;i+=2)
75     {
76         ll ls1=((jc[n]*ny[i])%mod*ny[n-i])%mod;
77         ll ls2=((((jc[i]*ny[i/2])%mod*ny[i/2])%mod*jc[i/2])%mod*ny[i/2+1])%mod;
78         ll ls3=((((jc[n-i]*ny[(n-i)/2])%mod*ny[(n-i)/2])%mod*jc[(n-i)/2])%mod*ny[(n-i)/2+1])%mod;
79         ans=(ans+(((ls1*ls2)%mod)*ls3)%mod)%mod;
80     }
81     printf("%lld\n",ans%mod);
82 }
83 int main()
84 {
85     scanf("%d%d",&n,&typ);  jc[0]=1;
86     for(int i=1;i<=2*n;++i)  jc[i]=(jc[i-1]*i)%mod;
87     ny[2*n]=ksm(jc[2*n],mod-2,mod);
88     for(int i=2*n;i>=1;--i)  ny[i-1]=(ny[i]*i)%mod;
89     if(typ==0)  work1();
90     else if(typ==1)  work2();
91     else if(typ==2)  work3();
92     else work4();
93     return 0;
94 }
数学+DP

猜你喜欢

转载自www.cnblogs.com/hzjuruo/p/11258141.html