Today is a sad story, all the people who rank higher than I have a first question
And my first question is zero.
But the happy thing is: The first question is not said to be a simple diagram, so the problem is wrong
No matter what, will wrong.
This afternoon broke the net, so this time only to write blog
First question
Because the topic did not give the concept of Eulerian graph, so I do not know what it is talking about, so it exploded zero
Then Eulerian graph is a simple diagram of the existence of the Euler circuit, with the following characteristics:
1. Unicom
2, the degrees are even
Obviously we will wrong see the topic, the number of Eulerian graph * (n (n-1)/2+1) can get the answer
Then it is easy to know that the number of graphs with even numbers of degrees is 2^ ((n-1) * (n-2)/2)
is to consider proposing one of the points, the remaining points of the arbitrary composition, and then for the proposed point and there is only one scheme to make the current graph degrees are even
After the DP using the principle can be used to find out the degree of connectivity is the number of even, the practice is to use the total-non-connected
is not connected to the only need to enumerate 1 the size of the Unicom block can be
Time complexity O (n^2)
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include < Algorithm>using namespace Std; typedef long LONG ll;const int maxn=2010;const int mod=1e9+7;int n; LL H[MAXN],G[MAXN],F[MAXN]; LL JC[MAXN],INV[MAXN]; ll Pow_mod (ll V,int p) {ll tmp=1; while (p) {if (p&1) Tmp=tmp*v%mod; v=v*v%mod;p>>=1; }return tmp;} LL C (int n,int m) {return jc[n]*inv[m]%mod*inv[n-m]%mod;} int main () {scanf ("%d", &n); Jc[0]=1; for (int i=1;i<=n;++i) Jc[i]=jc[i-1]*i%mod; Inv[n]=pow_mod (jc[n],mod-2); for (int i=n-1;i>=0;--i) inv[i]=inv[i+1]* (i+1)%mod; h[1]=1;f[1]=1;g[1]=0; for (int i=2;i<=n;++i) H[i]=pow_mod (2LL, (i-1) * (i-2)/2); for (int i=2;i<=n;++i) {f[i]=h[i]; for (int j=1;j<=i-1;++j) {f[i]=f[i]-c (i-1,j-1) *f[j]%mod*h[i-j]%mod; if (f[i]<0) F[i]+=mod; }}f[n]=f[n]+n* (n-1) *pow_mod (2ll,mod-2)%mod*f[n]%mod; if (f[n]>=mod) F[n]-=mod; printf ("%lld\n", F[n]); return 0;}
And then it's easy to see that the formula is a convolution form when it's not connected.
So we can FFT, I am idle bored write a cdq+fft
Since modulus is not very supportive, we have to do 9 DFT each time
Then although the theoretical Complexity O (nlog^2n), but can only run over 20000 of the data Qaq
#include <cstdio> #include <cstring> #include <iostream> #include <cstdlib> #include < algorithm> #include <cmath> #define G 3using namespace Std;const int maxn=400010;typedef long long ll;int n,n,len; const int Mod=1e9+7;const int M=30000;const long double pi=acos ( -1.0); int Jc[maxn],inv[maxn];int H[maxn],f[maxn];int Rev [Maxn],num[22];int a[maxn],b[maxn],c[maxn];int a0[maxn],b0[maxn],a1[maxn],b1[maxn];struct Cpx{long Double r,i;cpx ( Long double R=0,long Double i=0): R (R), I (i) {}}A[MAXN],B[MAXN],C[MAXN];CPX operator + (const CPX &a,const cpx &b) { Return CPX (A.R+B.R,A.I+B.I);} CPX operator-(const CPX &a,const cpx &b) {return CPX (A.R-B.R,A.I-B.I);} CPX operator * (const CPX &a,const cpx &b) {return CPX (A.R*B.R-A.I*B.I,A.R*B.I+A.I*B.R);} void FFT (CPX *a,int n,int type) {for (Int. i=0;i<n;++i) if (I<rev[i]) swap (a[i],a[rev[i]]); for (int k=0; (1<<k) <N;++K) {int m= (1<<k), m2= (m<<1); long double o=2*pi/m2*type;cpx wn (cos (o), sin (o)); for (int i=0;I<N;I+=M2) {CPX W (1,0); for (int j=0;j<m;++j) {CPX x=a[i+j],y=a[i+j+m]*w; A[i+j]=x+y; A[i+j+m]=x-y;w=w*wn;}}} if (type==-1) for (int i=0;i<n;++i) a[i].r/=n;} void Mul (int *a,int *b,int *c) {for (int i=0;i<n;++i) A[I]=CPX (a[i],0), B[I]=CPX (b[i],0); FFT (a,n,1); FFT (b,n,1); for (int i=0;i<n;++i) a[i]=a[i]*b[i]; FFT (A,n,-1), for (int i=0;i<n;++i) c[i]= ((LL) (a[i].r+0.5))%mod;} void Mul_mod (int *a,int *b,int *c) {for (int i=0;i<n;++i) A0[i]=a[i]/m,b0[i]=b[i]/m;mul (A0,B0,A0), for (int i=0;i<n ; ++i) {c[i]=1ll*a0[i]*m%mod*m%mod;a1[i]=a[i]%m;b1[i]=b[i]%m;} Mul (A1,B1,A1); for (int i=0;i<n;++i) {c[i]=c[i]+a1[i];if (c[i]>=mod) c[i]-=mod;a1[i]=a1[i]+a0[i];if (a1[i]>= MoD) a1[i]-=mod;a0[i]=a[i]/m+a[i]%m;b0[i]=b[i]/m+b[i]%m;} Mul (a0,b0,a0); for (int i=0;i<n;++i) {c[i]=c[i]+1ll*m* (a0[i]-a1[i]+mod)%mod;if (C[i]>=mod) C[i]-=mod;} return;} ll Pow_mod (ll V,int p) {ll tmp=1;while (p) {if (p&1) tmp=tmp*v%mod;v=v*v%mod;p>>=1;} return TMP;} void Solve (int l,int R) {if (l==r) Return;int mid= (l+r) >>1; Solve (L,mid); for (n=1,len=0; n< (r-l+1); n<<=1,len++); for (int i=0;i<n;++i) rev[i]=rev[i>>1]>>1| ((i&1) << (len-1)); for (int i=0;i<n;++i) a[i]=b[i]=0;for (int i=l;i<=mid;++i) a[i-l]=1ll*f[i]*inv[i-1] %mod;for (int i=0;i<n;++i) b[i]=h[i];mul_mod (a,b,c); for (int i=mid+1;i<=r;++i) {f[i]=f[i]-1ll*jc[i-1]*c[i-l]% Mod;if (f[i]<0) F[i]+=mod;} Solve (mid+1,r);} int main () {scanf ("%d", &n), jc[0]=1;for (int i=1;i<=n;++i) Jc[i]=1ll*jc[i-1]*i%mod;inv[n]=pow_mod (jc[n],mod-2 ); for (int i=n-1;i>=0;--i) inv[i]=1ll*inv[i+1]* (i+1)%mod;h[1]=1;f[1]=1;for (int i=2;i<=n;++i) {H[i]=pow_mod ( 2LL, (i-1) * (i-2)/2); f[i]=h[i];h[i]=1ll*h[i]*inv[i]%mod;} Solve (1,n); f[n]=f[n]+1ll*n* (n-1) *pow_mod (2ll,mod-2)%mod*f[n]%mod;if (f[n]>=mod) f[n]-=mod;printf ("%d\n", F[n]) ; return 0;}
Second question
Today the second question has been stuck 10 points constant, but also learned some new tricks, also is a blessing in disguise
It is clear that we should consider splitting, and there are two ways of splitting the rule:
The first is the solution, we split the two halves, and then we counted the middle answer.
Maintain a pointer to the left and right, each time to the maximum value of a small extension, so as to ensure that when one side as the maximum value, the other side must be a large expansion interval
And then in the process of the sweep with an array to save the prefix and or suffix and then you can
This is actually a bit of a hassle, because either the prefix maximum or the suffix maximum is monotonous
The end of the corresponding maximal interval is also monotonous, we just need to use the monotony sweep the left and then sweep again to the right.
Pay attention to sweep because the maximum value may be at the same time on the left and the right side, so we sweep the left side of the rule is strictly less than the right side, sweep the right side of the left is less than equal to the
Complexity O (NLOGN)
The second approach is to consider finding the maximum value of the current interval and splitting it into two halves.
We just need to count the middle answer, this time the maximum is fixed, the answer is easy to count
But notice here we theoretically can not sweep all over again, because here is not evenly divided in half, sweep around the limit Complexity O (n^2)
The author later said the data was random qaq and then there was a man in the exam room. (Random Data complexity O (NLOGN))
It's easy to see that we don't have to write division, preprocess each point with a monotone queue to the left and right end of the maximum and then brute force sweep.
Time complexity is the same as the above, although the data can be random, but not very graceful, because it can be jammed
We will find that the problem is converted to the enumeration side to count the number of x on the other side, obviously we can use heuristic thinking, each time we enumerate the shorter side
It is not difficult to find each point is enumerated every time, its interval length is at least/2, so the contribution of each point to the enumeration is O (LOGN)
The time complexity of the enumeration is O (Nlogn), and then the query is apparently done with a persisted segment tree
Total time complexity O (nlog^2n), because such a division may explode stack, so I wrote a BFS in the examination room, the results were stuck 10 points constant
Optimized the Chairman tree on a, as for the Chairman tree optimization if you find that the current interval is 0, you don't have to go down recursively (this is a great optimization for the chairman tree, because think about the chair tree's build process.) )
Later found that the data is random, DFS will not explode stack, change to DFS does not optimize the chairman of the tree can also a, the examination room to think more qaq worry sang ing
But this is more than the complexity of the log, can continue to optimize it? OK!
YMX proposed that you will find the DFS process we do not ask, while the inquiry is split into two prefixes asked to do offline, asking for a maximum of O (NLOGN)
Not difficult to find due to the nature of Dfs, finally get the inquiry sequence naturally ordered, after we go offline O (n) sweep once can O (NLOGN) processing all inquiries
Time complexity O (NLOGN), the actual measurement is not sure where to go
Post the morning code as an optimization souvenir for the Chairman tree:
#include <cstdio> #include <iostream> #include <cstdlib> #include <algorithm> #include < Cstring> #include <queue>using namespace std; typedef long LONG Ll;const int maxn=300010;int n,k,mod;int a[maxn];int vis[1000010],tot=0;int mx[maxn<<2],pos[ Maxn<<2];int Sum[maxn];int CNT=0,RT[MAXN]; LL ans=0;struct seg_tree{int l,r,v;} t[8000010];struct op{int l,r; OP (int l=0,int r=0): L (L), R (r) {}};queue<op>q;void read (int &num) {Num=0;char Ch=getchar (); while (ch< '! ') Ch=getchar (); while (ch>= ' 0 ' &&ch<= ' 9 ') num= (num<<1) + (num<<3) +ch-' 0 ', Ch=getchar ();} void Build_tree (int o,int l,int R) {if (l==r) {mx[o]=a[l];p Os[o]=l;return;} int mid= (L+R) >>1; Build_tree (O<<1,l,mid); Build_tree (O<<1|1,MID+1,R); if (mx[o<<1]>mx[o<<1|1]) mx[o]=mx[o<<1],pos[o]=pos[o<<1]; else mx[o]=mx[o<<1|1],pos[o]=pos[o<<1|1];} PAIR<INT,INT>ASK_MX (int o,int l,int r,int x,inT y) {if (l>=x&&r<=y) return Make_pair (Mx[o],pos[o]); int mid= (L+R) >>1; if (Y<=mid) return ask_mx (o<<1,l,mid,x,y); else if (X>mid) return ask_mx (o<<1|1,mid+1,r,x,y); else{pair<int,int>a=ask_mx (o<<1,l,mid,x,y); PAIR<INT,INT>B=ASK_MX (O<<1|1,mid+1,r,x,y); if (A.first>b.first) return A; return B; }}void Build (int &o,int l,int R) {o=++cnt; if (l==r) return; int mid= (L+R) >>1; Build (T[o]. L,L,MID); Build (T[o]. R,MID+1,R);} void UPD (int &o,int l,int r,int p) {t[++cnt]=t[o];o=cnt; if (l==r) {T[o].v++;return;} int mid= (L+R) >>1; if (p<=mid) UPD (T[o]. L,L,MID,P); else UPD (T[o]. R,MID+1,R,P); T[o].v=t[t[o]. L].v+t[t[o]. R].V;} int ask (int a,int b,int l,int r,int p) {if (a==b) return 0; if (l==r) return t[a].v-t[b].v; int mid= (L+R) >>1; if (P<=mid) return Ask (T[a]. L,T[B]. L,L,MID,P); else return ask (T[a]. R,T[B]. R,MID+1,R,P);} void BFS () {Q.push (OP (2,n)); while (! Q.empty ()) {OP tmp=q.front (); Q.pop (); int l=tmp. L,r=tmp. R int P=ask_mx (1,1,N,L,R). Second; if (l<p-1) Q.push (OP (l,p-1)); if (p+1<r) Q.push (OP (p+1,r)); int len=p-l,ren=r-p; if (ren<len) {int tmp=sum[p]-a[p]+mod; if (tmp>=mod) Tmp-=mod; if (Vis[tmp]) Tmp=ask (rt[p-2],rt[l-2],1,tot,vis[tmp]); else tmp=0; ans+=tmp; for (int i=p+1;i<=r;++i) {tmp=sum[i]-a[p]+mod; if (tmp>=mod) Tmp-=mod; if (!vis[tmp]) continue; Tmp=ask (Rt[p-1],rt[l-2],1,tot,vis[tmp]); ans+=tmp; }}else{int tmp=sum[p-1]+a[p]; if (tmp>=mod) Tmp-=mod; if (Vis[tmp]) Tmp=ask (rt[r],rt[p],1,tot,vis[tmp]); else tmp=0; ans+=tmp; for (int i=l-1;i<=p-2;++i) {tmp=sum[i]+a[p]; if (tmp>=mod) Tmp-=mod; if (!vis[tmp]) continue; Tmp=ask (Rt[r],rt[p-1],1,tot,vis[tmp]); ans+=tmp; }}}return;} int main () {read (n); read (k); n++;mod=k; for (int i=2;i<=n;++i) read (A[i]); Build_tree (1,1,n); Vis[0]=++tot; for (int i=2;i<=n;++i) {a[i]%=k; Sum[i]=sum[i-1]+a[i]; if (sum[i]>=k) sum[i]-=k; if (!vis[sum[i]]) Vis[sum[i]]=++tot; } build (Rt[0],1,tot); for (int i=1;i<=n;++i) {rt[i]=rt[i-1]; UPD (Rt[i],1,tot,vis[sum[i]); } BFS (); printf ("%lld\n", ans); return 0;}
Third question
We consider the case that the tree is a chain, we maintain the longest contiguous sub-segments with the line segment tree and we Can
So for a tree, we can use the tree chain to transform into a chain of cases
But notice that the Unicom block may be the concatenation of the chain and the chain, so we define a point right is the maximum prefix of all his sons and his different chains (minus 0) and his own point right
So the longest continuous sub-segment and the maximum value of all the chains is the answer.
We turn the changes into incremental changes
Modify the Logn bar chain at most each time you modify, we can maintain the affected points when we jump up.
About half an hour before the exam, and then the test found may be t
Then it took another half an hour to get the card constant, optimize the build process, and then practice a tree-shaped DP.
The results are still rank1qaq.
It is worth mentioning that maintaining the longest continuous field of all the chains and can be used in the heap, but I used another line in the Examination room tree Qaq
#include <cstdio> #include <cstring> #include <iostream> #include <cstdlib> #include < Algorithm>using namespace Std; const int Maxn=100010;int n,m,u,v,type;int c[maxn];int h[maxn],cnt=0;struct edge{int to,next;} G[maxn<<1];int dep[maxn],sz[maxn],son[maxn],fa[maxn];int L[maxn],r[maxn],pos[maxn],fp[maxn],tot;int P[MAXN] , Top[maxn],sum;int mx[maxn<<2];int dp[maxn],tmp[maxn];struct seg_tree{int suf,pre,mx,sum;} t[maxn<<2]; void read (int &num) {int F=1;num=0;char ch=getchar (); while (ch< '! ') Ch=getchar (); if (ch== '-') F=-1,ch=getchar (); while (ch>= ' 0 ' &&ch<= ' 9 ') num= (num<<1) + (num<<3) +ch-' 0 ', Ch=getchar (); Num*=f;} void Add (int x,int y) {++cnt; G[cnt].to=y; g[cnt].next=h[x];h[x]=cnt;} void DFS (int u,int f) {sz[u]=1;fa[u]=f; for (int i=h[u];i;i=g[i].next) {int v=g[i].to; if (v==f) continue; dep[v]=dep[u]+1; DFS (V,u); SZ[U]+=SZ[V]; if (Sz[son[u]]<sz[v]) son[u]=v;}return;} void Get_pos (int u,int f) {top[u]=f;pos[u]=++tot;fp[tot]=u; if (u==f) {sum++; L[sum]=tot;} P[u]=sum; if (!son[u]) {R[sum]=tot;return;} Get_pos (SON[U],F); for (int i=h[u];i;i=g[i].next) {int v=g[i].to; if (v==fa[u]| | V==son[u]) continue; Get_pos (V,V); }return;} int Max (int a,int b) {return a>b?a:b;} void UPD (int o,int l,int r,int P,int v) {if (l==r) {t[o].suf+=v;t[o].pre+=v; T[o].mx+=v;t[o].sum+=v; Return } int mid= (L+R) >>1; if (p<=mid) UPD (O<<1,L,MID,P,V); else UPD (O<<1|1,MID+1,R,P,V); int l= (o<<1), r= (l|1); T[o].sum=t[l].sum+t[r].sum; T[o].suf=max (T[r].suf,t[r].sum+t[l].suf); T[o].pre=max (T[l].pre,t[l].sum+t[r].pre); T[o].mx=max (t[l].mx,t[r].mx); T[o].mx=max (T[o].mx,t[l].suf+t[r].pre);} void build (int o,int l,int R) {if (l==r) {int u=fp[l]; T[o].suf=t[o].pre=t[o].mx=t[o].sum=dp[u]; Return } int mid= (L+R) >>1; Build (O<<1,l,miD); Build (O<<1|1,mid+1,r); int l= (o<<1), r= (l|1); T[o].sum=t[l].sum+t[r].sum; T[o].suf=max (T[r].suf,t[r].sum+t[l].suf); T[o].pre=max (T[l].pre,t[l].sum+t[r].pre); T[o].mx=max (t[l].mx,t[r].mx); T[o].mx=max (T[o].mx,t[l].suf+t[r].pre);} Seg_tree Ask (int o,int l,int r,int x,int y) {if (l>=x&&r<=y) return t[o]; int mid= (L+R) >>1; if (Y<=mid) return ask (O<<1,l,mid,x,y); else if (X>mid) return ask (O<<1|1,mid+1,r,x,y); else{seg_tree A=ask (o<<1,l,mid,x,y); Seg_tree B=ask (o<<1|1,mid+1,r,x,y), C; C.sum=a.sum+b.sum; C.suf=max (B.suf,b.sum+a.suf); C.pre=max (A.pre,a.sum+b.pre); C.mx=max (a.mx,b.mx); C.mx=max (C.mx,a.suf+b.pre); return C; }}void Modify (int o,int l,int r,int P,int v) {if (l==r) {Mx[o]=v;return;} int mid= (L+R) >>1; if (p<=mid) modify (O<<1,L,MID,P,V); else modify (O<<1|1,MID+1,R,P,V); Mx[o]=max (MX[O<<1],MX[O<<1|1]);} void get_upd (int u,int v) {while (u!=-1) {Seg_tree a=ask (1,1,n,l[p[u]],r[p[u]]); UPD (1,1,N,POS[U],V); Seg_tree B=ask (1,1,n,l[p[u]],r[p[u]); Modify (1,1,sum,p[u],b.mx); if (b.pre<0) b.pre=0; if (a.pre<0) a.pre=0; U=fa[top[u]];v=b.pre-a.pre; }return;} void get_dp (int u,int f) {dp[u]=c[u];tmp[u]=c[u]; if (!son[u]) return; for (int i=h[u];i;i=g[i].next) {int v=g[i].to; if (v==f| | V==son[u]) continue; GET_DP (V,u); if (tmp[v]>0) dp[u]+=tmp[v]; }GET_DP (Son[u],u); if (tmp[son[u]]>0) tmp[u]=dp[u]+tmp[son[u]]; else tmp[u]=dp[u];} int main () {read (n); read (m); for (int i=1;i<=n;++i) read (C[i]); for (int i=1;i<n;++i) {read (u); Read (v); Add (u,v); add (V,u); }dfs (1,-1); Get_pos (a); GET_DP (1,-1); build (1,1,n); for (int i=1;i<=n;++i) printf ("%d%d\n", dp[i],tmp[i]); for (int i=1;i<=sum;++i) {Seg_tree a=ask (1,1,n,l[i],r[i]); Modify (1,1,sum,i,a. mx); }//for (int i=1;i<=n;++i) GET_UPD (I,c[i]); for (int i=1;i<=n;++i) printf ("%d\n", ask (1,1,n,pos[i],pos[i]). sum); while (m--) {read (type); if (type==2) printf ("%d\n", Max (mx[1],0)); else{read (u); Read (v); V=v-c[u];c[u]+=v; GET_UPD (U,V); }} return 0;}
Today the exam learned some of the Chairman tree optimization techniques
Although the exam is stuck constant, and the second question data randomly by a big wave of water passed, very sad
But it's nice to learn new knowledge, Qaq.
Feel their own data structure ability is very good, generally have the idea of the need to maintain what data structure of the topic can be written quickly
Basically don't have to change to be able to shoot (except top_tree what)
The topic slightly some pits, the first question Eulerian graph caused own knowledge barrier, then can not understand the question to be able to explode zero
What's left of the question: some questions about the counting of graphs? I don't know if I can find it.
5.28 Exam Revision + Summary