4.1省選模擬
阿新 • • 發佈:2022-04-01
回想上次過愚人節還是在上次,那下次過愚人節應該在下次了
\(T1\)
\(dis(x,y)=dep(x)+dep(y)-2\times dep(lca(x,y))\)
顯然重心最優
然後做一個匹配即可
#define Eternal_Battle ZXK #include<bits/stdc++.h> #define int long long #define MAXM 200005 #define MAXN 200005 using namespace std; int head[MAXN],nxt[MAXN],val[MAXN],siz[MAXN],to[MAXN],tot; int Max[MAXN],Ans,rt,n; void add(int u,int v,int w) { tot++; to[tot]=v; val[tot]=w; nxt[tot]=head[u]; head[u]=tot; } void dfs_rt(int now,int fa) { siz[now]=1; for(int i=head[now];i;i=nxt[i]) { int y=to[i]; if(y==fa) continue; dfs_rt(y,now); siz[now]+=siz[y]; Max[now]=max(Max[now],siz[y]); } Max[now]=max(Max[now],n-siz[now]); if(Max[now]<Max[rt]) rt=now; } void dfs(int now,int fa,int dep) { Ans+=2*dep; for(int i=head[now];i;i=nxt[i]) { int y=to[i]; if(y==fa) continue; dfs(y,now,dep+val[i]); } } int vis[MAXN],Sum[MAXN]; set<int> In[MAXN]; set<int> Min; set<pair<int,int> > Set; void dfs_vis(int now,int fa,int fg) { siz[fg]++; In[fg].insert(now); vis[now]=fg; for(int i=head[now];i;i=nxt[i]) { int y=to[i]; if(y==fa) continue; dfs_vis(y,now,fg); } } void Link(int x,int y) { // cout<<"Link: "<<x<<" "<<y<<endl; int p=vis[x],q=vis[y]; Min.erase(y); if(p) { Set.erase(make_pair(Sum[p],p)); Set.insert(make_pair(--Sum[p],p)); } if(q) { In[q].erase(y); if(!In[q].empty()) Min.insert(*In[q].begin()); Set.erase(make_pair(Sum[q],q)); Set.insert(make_pair(--Sum[q],q)); } } int sol(int x) { int res; if(Set.rbegin()->first==n-x+1&&Set.rbegin()->second!=vis[x]) { res=*In[Set.rbegin()->second].begin(); } else { res=vis[*Min.begin()]!=vis[x]||x==rt?*Min.begin():*next(Min.begin()); } Link(x,res); return res; } signed main() { freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); scanf("%lld",&n); for(int i=1,u,v,w;i<n;i++) { scanf("%lld%lld%lld",&u,&v,&w); add(u,v,w); add(v,u,w); } Max[0]=n; dfs_rt(1,1); dfs(rt,rt,0); cout<<Ans<<"\n"; if(n==1) { puts("1"); return 0; } Min.insert(rt); for(int i=head[rt];i;i=nxt[i]) { int y=to[i]; siz[y]=0; dfs_vis(y,rt,y); Min.insert(*In[y].begin()); Set.insert(make_pair(Sum[y]=siz[y]*2,y)); } for(int i=1;i<=n;i++) { cout<<sol(i)<<" "; } }
\(T2\)
誠不欺我,果然有\(dp\)
\(k<=12\)可以狀壓,\(m<=4\)那麼狀態轉移數目較少
那麼轉移易得
\(dp[i][j][S]\)表示我們目前填第\(i\)個數字,已經填了\(j\)個位置,目前大於等於\(i-m\)的位置有哪些的方案數
由於我們是遞增填數,就可以實時更新,又因為每個數不同,那麼記錄一下哪些在原序列裡就好了
#include <bits/stdc++.h> #define mod 1000000007 #define MAXN 205 using namespace std; int n,k,m,Sum; struct Mat { int jz[MAXN][MAXN]; Mat operator * (Mat x) { Mat res; memset(res.jz,0,sizeof(res.jz)); for(int i=0;i<=Sum;i++) { for(int j=0;j<=Sum;j++) { for(int k=0;k<=Sum;k++) { res.jz[i][j]=(res.jz[i][j]+1ll*jz[i][k]*x.jz[k][j])%mod; } } } return res; } }b,St; int main() { cin>>n>>k>>m; Sum=k<<m; for(int i=0;i<k;i++) { for(int j=0;j<(1<<m);j++) { int Sit=(j<<1)&(1 << m)-1; int num=1+__builtin_popcount(j); b.jz[(i<<m)+j][(i<<m)+Sit]=1; if(i==k-1) b.jz[(i<<m)+j][Sum]=num; else b.jz[(i<<m)+j][(i+1<<m)+Sit+1]=num; } } b.jz[Sum][Sum]=St.jz[0][0]=1; while(n) { if(n&1) St=St*b; b=b*b; n>>=1; } cout<<St.jz[0][Sum]<<endl; return 0; }
\(T3\)
大家都會猜結論\(QAQ,\)誰能教教我怎麼猜中啊
考慮交換的中心點必然\(p_i=i\)
然後把\(p_i=i\)去掉,分為若干區間,區間內部值域相等
若出現超過長度為\(3\)的下降子序列就不合法
#include<bits/stdc++.h> #define MAXN 600005 using namespace std; int n,p[MAXN],a[MAXN],Min[MAXN]; int stk[MAXN],top; int main() { cin>>n; for(int i=1;i<=n;i++) { scanf("%d",&p[i]); } p[n+1]=n+1,p[0]=0; for(int i=1;i<=n;i++) { if(p[i-1]!=i-1&&p[i]!=i&&p[i+1]!=i+1) { puts("No"); return 0; } a[i]=(i==p[i]); } for(int i=1,j;i<=n;i=j+1) { for(j=i;j<n&&a[j]!=a[j+1];j++); top=0; for (int k=i;k<=j;k++) { if(p[k]<i||j<p[k]) { puts("No"); return 0; } if(!a[k]) stk[++top]=p[k]; } Min[top]=stk[top]; for(int k=top-1;k>=1;k--) { Min[k]=min(Min[k+1],stk[k]); } int Max=stk[1]; for(int k=2;k<top;k++) { Max=max(Max,stk[k]); if(Min[k]<stk[k]&&stk[k]<Max) { puts("No"); return 0; } } } puts("Yes"); return 0; }