Day 2
T1
二分圖的部分分直接二分能夠獲得三個點,一個入度一個出度一個顏色相等。c++
而後你能夠詢問兩次看顏色相等和入度是哪兩個(詢問答案是1),就能作了。spa
非二分圖每次暴力看能不能加入當前集合,而後再把剩下的點查詢邊而且對剩下的點遞歸下去。code
容易證實次數是 $3n\log n + 3n + 2n + 2n$ 左右。遞歸
#include "chameleon.h" #include<bits/stdc++.h> using namespace std; vector<int> st[1010]; bool in[1010]; int c[1010][1010]; map<vector<int>,int> Q; int Tim; int Qry(vector<int> s){ sort(s.begin(),s.end()); if(Q.find(s)!=Q.end())return Q[s]; ++Tim; return Q[s]=Query(s); } inline void Div(vector<int> s,int added){ if(!s.size())return ; if(s.size()==1){ st[added].push_back(s[0]); st[s[0]].push_back(added); return ; } vector<int> Div1,Div2; int sz = s.size(); for(int i=0;i<sz;i++){ if(i<sz/2)Div1.push_back(s[i]); else Div2.push_back(s[i]); } if(Div1.size()){ Div1.push_back(added); int q1=Div1.size()-1; int q2=Qry(Div1); Div1.pop_back(); if(q2<=q1){ Div(Div1,added); } else{ Div(Div2,added); } }else Div(Div2,added); } vector<int> ers(vector<int> s,int t){ vector<int> q; for(size_t i=0;i<s.size();i++){ if(s[i]!=t)q.push_back(s[i]); }return q; } void Solve(int N) { for(int i=0;i<=N*2;i++){ st[i].clear(); in[i]=0; } int csz=0; while(csz<N*2){ vector<int> cur; int c = 0; vector<int> v2; for(int i=1;i<=N*2;i++)if(!in[i]){ cur.push_back(i); int q=Qry(cur); if(q<=c){ cur.pop_back(); v2.push_back(i); } else{ c=q; in[i]=1; csz++; } } for(size_t i=0;i<v2.size();i++){ vector<int> v3=cur; while(1){ int sz=v3.size(); v3.push_back(v2[i]); int q=Qry(v3); v3.pop_back(); if(q<=sz){ Div(v3,v2[i]); v3=ers(v3,st[v2[i]].back()); }else break; } } } for(int i=1;i<=N*2;i++)in[i]=0; for(int i=1;i<=N*2;i++)for(int j=1;j<=N*2;j++)c[i][j]=0; for(int i=1;i<=N*2;i++){ if(st[i].size()>2){ assert(st[i].size()==3); int sz=st[i].size(); int t=0; for(int k=0;k<sz;k++)for(int k2=k+1;k2<sz;k2++){ ++t; vector<int> sq; sq.push_back(i),sq.push_back(st[i][k]),sq.push_back(st[i][k2]); if(t==3||Qry(sq)==1){ for(int t=1;t<=2;t++)c[i][sq[t]]=1; goto END; } } END:; }else{ for(size_t j=0;j<st[i].size();j++){ c[i][st[i][j]]=1; } } } for(int i=1;i<=N*2;i++){ for(int j=1;j<=N*2;j++){ if(!in[i]&&!in[j]&&c[i][j]&&c[j][i]){ Answer(i,j); in[i]=in[j]=1; } } } return ; }
T2
啓發式合併便可。ci
#include<bits/stdc++.h> using namespace std; const int N = 1e5+5; const int M = 3e5+5; typedef long long ll; typedef pair<int,int> pi; int sz[N],fa[N]; inline int find(int x){return fa[x]==x?fa[x]:fa[x]=find(fa[x]);} int n,m; vector<pi> stk; map<int,set<int> > Eout[N]; map<int,set<int> > Ein[N]; ll ans = 0; int Ot[N],In[N]; inline void merge(int u,int v){ int sz1=In[u]+Ot[u], sz2 = In[v]+Ot[v]; if(sz1>sz2)swap(sz1,sz2),swap(u,v); fa[u]=v; for(map<int,set<int> >::iterator it=Eout[u].begin();it!=Eout[u].end();it++){ for(set<int>::iterator j=it->second.begin();j!=it->second.end();j++){ int _u=*j; int to=it->first; Ein[to][u].erase(_u); In[to]--; if(Ein[to][u].size()==0){Ein[to].erase(u);} ans-=sz[to]; stk.push_back(pi(_u,to)); } } for(map<int,set<int> >::iterator it=Ein[u].begin();it!=Ein[u].end();it++){ for(set<int>::iterator j=it->second.begin();j!=it->second.end();j++){ int _u=*j; int to=it->first; Eout[to][u].erase(_u); Ot[to]--; if(Eout[to][u].size()==0){Eout[to].erase(u);} ans-=sz[u]; stk.push_back(pi(_u,u)); } } ans-=1ll*sz[u]*(sz[u]-1); ans-=1ll*sz[v]*(sz[v]-1); ans+=1ll*sz[u]*In[v]; sz[v]+=sz[u]; ans+=1ll*sz[v]*(sz[v]-1); } inline void adde(int u,int v){ int fu=find(u), fv=find(v); if(fu==find(v))return ; if(Eout[fu].find(fv)!=Eout[fu].end()&&Eout[fu][fv].find(u)!=Eout[fu][fv].end()) {return ;} Eout[fu][fv].insert(u); Ein[fv][fu].insert(u); Ot[fu]++, In[fv]++; ans+=sz[fv]; if(Eout[fv].find(fu)!=Eout[fv].end()&&Eout[fv][fu].size()) {merge(fu,fv);} } int main() { cin >> n >> m; for(int i=1;i<=n;i++){ fa[i]=i,sz[i]=1; } for(int i=1;i<=m;i++){ int u,v;scanf("%d%d",&u,&v); stk.push_back(pi(u,v)); while(stk.size()){ pi d = stk.back(); stk.pop_back(); adde(d.first,d.second); } printf("%lld\n",ans); } }
T3
判斷的作法是從後向前,每次找一個最大的沒有被佔領的,小於等於 $w_i$ 的位置(若是沒有則最後成爲了0)it
把兩個數字相等當作兩個不一樣的數,最後除 $2^n$ 便可。class
$g[i][j]$ 表示 $i$ 個數,$1$ 到 $j$ 已經被佔領了,知足前 $i$ 個沒有最後成爲了 $0$ 的方案數。map
轉移用 $g[k-1][k-1]$ 就好了。(具體能夠看代碼)im
$f[i][j]$ 即以上的東西加上每一個位置是否成爲了 $0$ 的限制。轉移是相似的。問答
#include<bits/stdc++.h> using namespace std; const int N = 610; typedef long long ll; const int mod = 1e9+7; inline int add(int a,int b){a+=b;return a>=mod?a-mod:a;} inline int sub(int a,int b){a-=b;return a<0?a+mod:a;} inline int mul(int a,int b){return 1ll*a*b%mod;} inline int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;} /* math */ int g[N][N],h[N],n; int f[N<<1][N],a[N]; int bin[N<<1][N<<1]; int main() { cin >> n; for(int i=1;i<=n;i++)scanf("%d",&a[i]); reverse(a+1,a+n+1); bin[0][0]=1;for(int i=1;i<=n;i++){ bin[i][0]=1;for(int j=1;j<=i;j++)bin[i][j]=add(bin[i-1][j],bin[i-1][j-1]); } g[0][0]=1; h[0]=1; for(int i=1;i<=n;i++){ for(int j=0;j<=i;j++){ g[i][j]=add(g[i][j], g[i-1][j]); for(int k=1;k+j<=i;k++){ g[i][j+k] = add(g[i][j+k], mul(g[i-1][j], mul(bin[i-1-j][k-1], mul(h[k-1],1+k)))); } } h[i] = g[i][i]; } f[0][0]=1; a[0]=n*2+1; for(int i=1;i<=n+1;i++){ int d = a[i-1]-a[i]-1; for(int j=0;j<i;j++){ int h=j-(n*2-a[i-1]-(i-2)); for(int q=0;q<d;q++){ f[i-1][j]=mul(f[i-1][j], h-q); } } if(i<=n) for(int j=0;j<=i;j++){ f[i][j]=add(f[i][j], f[i-1][j]); for(int k=1;k+j<=i;k++){ f[i][j+k] = add(f[i][j+k], mul(f[i-1][j], mul(bin[i-1-j][k-1], mul(h[k-1],1+k)))); } } } int inv2 = (mod+1)>>1; int ans = f[n][n]; for(int i=1;i<=n;i++)ans=mul(ans,inv2); cout << ans << endl; }