CodeCraft-19 and Codeforces Round #537 (Div. 2) 題解
阿新 • • 發佈:2019-02-22
print line 就是 class swa bit 自己 != 方程
傳送門
D. Destroy the Colony
首先明確題意:除了規定的兩種(或一種)字母要在同側以外,其他字母也必須在同側。
發現當每種字母在左/右邊確定之後,方案數就確定了,就是分組的方案數乘\(\frac{((n/2)!)^2}{\prod cnt_i!}\)。
分組的方案數考慮DP,設\(dp_{i,j}\)為前\(i\)個字母,占了左邊\(j\)個位置的方案數,則有:
\[
dp_{i,j}=dp_{i-1,j-cnt_i}+dp_{i-1,j}
\]
當\(i\)是指定字母時特判即可。
這樣復雜度為\(O(52^3n)\),無法通過。
考慮最多指定兩次字母,而且字母順序對結果沒有關系,可以先把所有的DP出來,然後假裝指定的兩個字母是最後兩個DP的,按照DP方程撤銷即可。
#include<bits/stdc++.h> clock_t t=clock(); namespace my_std{ using namespace std; #define pii pair<int,int> #define fir first #define sec second #define MP make_pair #define rep(i,x,y) for (int i=(x);i<=(y);i++) #define drep(i,x,y) for (int i=(x);i>=(y);i--) #define go(x) for (int i=head[x];i;i=edge[i].nxt) #define templ template<typename T> #define sz 101101 #define mod 1000000007 typedef long long ll; typedef double db; mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);} templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;} templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;} templ inline void read(T& t) { t=0;char f=0,ch=getchar();double d=0.1; while(ch>‘9‘||ch<‘0‘) f|=(ch==‘-‘),ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘) t=t*10+ch-48,ch=getchar(); if(ch==‘.‘){ch=getchar();while(ch<=‘9‘&&ch>=‘0‘) t+=d*(ch^48),d*=0.1,ch=getchar();} t=(f?-t:t); } template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);} char __sr[1<<21],__z[20];int __C=-1,__Z=0; inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;} inline void print(register int x) { if(__C>1<<20)Ot();if(x<0)__sr[++__C]=‘-‘,x=-x; while(__z[++__Z]=x%10+48,x/=10); while(__sr[++__C]=__z[__Z],--__Z);__sr[++__C]=‘\n‘; } void file() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); #endif } inline void chktime() { #ifndef ONLINE_JUDGE cout<<(clock()-t)/1000.0<<‘\n‘; #endif } #ifdef mod ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;} ll inv(ll x){return ksm(x,mod-2);} #else ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;} #endif // inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;} } using namespace my_std; int n,m,K; char s[sz]; int a[sz],aa[sz]; int cnt[233]; ll T; ll fac[sz],_fac[sz]; void init(){fac[0]=_fac[0]=1;rep(i,1,sz-1) fac[i]=fac[i-1]*i%mod,_fac[i]=inv(fac[i]);} ll C(int n,int m){return n>=m&&m>=0?fac[n]*_fac[m]%mod*_fac[n-m]%mod:0;} int sum[66]; ll dp[sz],cur[sz]; ll ans[66][66]; void Init() { rep(i,1,K) sum[i]=sum[i-1]+cnt[i]; dp[0]=1; int n=::n>>1; rep(i,1,K) drep(j,n,cnt[i]) dp[j]=(dp[j]+dp[j-cnt[i]])%mod; } ll solve(int x,int y) { int n=::n>>1; if ((cnt[x]>n&&x==y)||(cnt[x]+cnt[y]>n&&x!=y)) return 0; ll c=fac[n]*fac[n]%mod*inv(T)%mod; if (x==y) return c*dp[n]%mod; rep(i,0,n) cur[i]=dp[i]; rep(j,cnt[x],n) cur[j]=(cur[j]-cur[j-cnt[x]]+mod)%mod; rep(j,cnt[y],n) cur[j]=(cur[j]-cur[j-cnt[y]]+mod)%mod; return c*cur[n-cnt[x]-cnt[y]]*2%mod; } int main() { file(); cin>>(s+1);n=strlen(s+1); rep(i,1,n) a[i]=aa[i]=s[i]; sort(aa+1,aa+n+1);K=unique(aa+1,aa+n+1)-aa-1; rep(i,1,n) a[i]=lower_bound(aa+1,aa+K+1,a[i])-aa; rep(i,1,n) ++cnt[a[i]]; init();Init(); T=1;rep(i,1,K) T=T*fac[cnt[i]]%mod; rep(i,1,K) rep(j,1,K) ans[i][j]=solve(i,j); read(m); int x,y; while (m--) read(x,y),printf("%lld\n",ans[a[x]][a[y]]); return 0; }
E. Tree
顯然需要DP,但怎麽DP呢?
考慮每個點只被自己的祖先限制,可以把要DP的點按某種方法排序,使得每個點的祖先都在自己之前處理完畢,就可以了。
設\(dp_{i,j}\)表示前\(i\)個點,分成\(j\)個集合的方案數,則有:
\[
dp_{i,j}=dp_{i-1,j}+(j-f_x)\times dp_{i-1,j}
\]
其中\(f_x\)表示\(x\)的祖先數。
這時又發現按\(f_x\)從小到大排序,就可以滿足要求,於是就做完了。
註意出題人卡空間,DP需要滾掉一維。
#include<bits/stdc++.h> clock_t t=clock(); namespace my_std{ using namespace std; #define pii pair<int,int> #define fir first #define sec second #define MP make_pair #define rep(i,x,y) for (int i=(x);i<=(y);i++) #define drep(i,x,y) for (int i=(x);i>=(y);i--) #define go(x) for (int i=head[x];i;i=edge[i].nxt) #define templ template<typename T> #define sz 101010 #define mod 1000000007 typedef long long ll; typedef double db; mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);} templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;} templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;} templ inline void read(T& t) { t=0;char f=0,ch=getchar();double d=0.1; while(ch>‘9‘||ch<‘0‘) f|=(ch==‘-‘),ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘) t=t*10+ch-48,ch=getchar(); if(ch==‘.‘){ch=getchar();while(ch<=‘9‘&&ch>=‘0‘) t+=d*(ch^48),d*=0.1,ch=getchar();} t=(f?-t:t); } template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);} char sr[1<<21],z[20];int C=-1,Z=0; inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} inline void print(register int x) { if(C>1<<20)Ot();if(x<0)sr[++C]=‘-‘,x=-x; while(z[++Z]=x%10+48,x/=10); while(sr[++C]=z[Z],--Z);sr[++C]=‘\n‘; } void file() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); #endif } inline void chktime() { #ifndef ONLINE_JUDGE cout<<(clock()-t)/1000.0<<‘\n‘; #endif } #ifdef mod ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;} ll inv(ll x){return ksm(x,mod-2);} #else ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;} #endif // inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;} } using namespace my_std; int n,Q; struct hh{int t,nxt;}edge[sz<<1]; int head[sz],ecnt; void make_edge(int f,int t) { edge[++ecnt]=(hh){t,head[f]}; head[f]=ecnt; edge[++ecnt]=(hh){f,head[t]}; head[t]=ecnt; } int dfn[sz],son[sz],size[sz],dep[sz],top[sz],fa[sz],T; #define v edge[i].t void dfs1(int x,int fa) { ::fa[x]=fa;dep[x]=dep[fa]+1; size[x]=1; go(x) if (v!=fa) { dfs1(v,x); size[x]+=size[v]; if (size[v]>size[son[x]]) son[x]=v; } } void dfs2(int x,int fa,int tp) { top[x]=tp;dfn[x]=++T; if (son[x]) dfs2(son[x],x,tp); go(x) if (v!=fa&&v!=son[x]) dfs2(v,x,v); } #undef v int tr[sz]; void add(int x,int y){while (x<=n) tr[x]+=y,x+=(x&(-x));} int query(int x){int ret=0;while (x) ret+=tr[x],x-=(x&(-x));return ret;} int query(int x,int y){return query(y)-query(x-1);} int Query(int x,int y) { int ret=0; while (top[x]!=top[y]) { if (dep[top[x]]<dep[top[y]]) swap(x,y); ret+=query(dfn[top[x]],dfn[x]); x=fa[top[x]]; } if (dep[x]>dep[y]) swap(x,y); ret+=query(dfn[x],dfn[y]); return ret; } int a[sz]; int f[sz]; inline bool cmp(const int &x,const int &y){return f[x]<f[y];} ll dp[333]; int main() { file(); int x,y,K,m,rt; read(n,Q); rep(i,1,n-1) read(x,y),make_edge(x,y); dfs1(1,0);dfs2(1,0,1); while (Q--) { read(K,m,rt); rep(i,1,K) read(a[i]),add(dfn[a[i]],1); rep(j,1,m) dp[j]=0; dp[0]=1; rep(i,1,K) f[a[i]]=Query(rt,a[i])-1; sort(a+1,a+K+1,cmp); rep(i,1,K) { x=a[i]; drep(j,m,f[x]+1) dp[j]=(dp[j-1]+dp[j]*(j-f[x])%mod)%mod; rep(j,0,f[x]) dp[j]=0; } ll ans=0; rep(i,1,m) (ans+=dp[i])%=mod; printf("%lld\n",ans); rep(i,1,K) add(dfn[a[i]],-1); } return 0; }
CodeCraft-19 and Codeforces Round #537 (Div. 2) 題解