kangaroo
题意:
有n(n<=300)只袋鼠,袋鼠i的体积为ai,口袋大小为bi(ai>bi)。
把袋鼠i放入袋鼠j的口袋里。
要求此时袋鼠i和j的口袋里没有袋鼠,且袋鼠i,j不在其它袋鼠口袋里。
不断操作直到不能操作为止,有多少种不同的终止状态,对109+7取模。
分析:
考虑一种合法的终止状态。
一定存在一只袋鼠,比它小的袋鼠都被装了,能装它的袋鼠都装了其它袋鼠。
先将a和b分别排序。
然后枚举这只倒霉的袋鼠i,dp算出方案数。
将a和b都按是否大于ai分成左右两边。
用f[i][j]表示a中左边前i个与b中左边匹配j对的方案数。
用g[i][j]表示b中右边前i个与a中右边匹配j对的方案数。
枚举a中左边与b中右边匹配的对数k,则这k对有k!种匹配方法。
再乘上ab两边分别匹配的方案数,就是所有的方案数。
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define g() getchar() template<class Q>inline void Scan(Q&x){ char c; while(c=g(),c<48||c>57); for(x=0;c>47&&c<58;c=g())x=10*x+c-48; } #define rep(i,a,b) for(int i=a;i<b;++i) #define dat(i,a,b) for(int i=a;i>b;--i) const int MAXN=305; const int Mod=1e9+7; int n,ans; int fac[MAXN]; int f[MAXN][MAXN],g[MAXN][MAXN]; int a[MAXN],b[MAXN]; inline void Init(){ Scan(n); rep(i,1,n+1){ Scan(a[i]),Scan(b[i]); } sort(a+1,a+1+n); sort(b+1,b+1+n); fac[0]=1; rep(i,1,n+1) fac[i]=1ll*fac[i-1]*i%Mod; } inline void Solve(){ rep(wuke,1,n+1){ memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); int r=upper_bound(b+1,b+n+1,a[wuke])-b; f[0][0]=1; rep(i,1,r) rep(j,0,i+1){ f[i][j]=f[i-1][j]; int x=lower_bound(a+1,a+wuke,b[i])-a-1; if(j&&x-j+1>0){ f[i][j]=(f[i][j]+1ll*f[i-1][j-1]*(x-j+1)%Mod)%Mod; } } g[n+1][0]=1; dat(i,n,wuke) rep(j,0,n-i+2){ g[i][j]=g[i+1][j]; int x=n-(upper_bound(b+r,b+n+1,a[i])-b)+1; if(j&&x-j+1>0){ g[i][j]=(g[i][j]+1ll*g[i+1][j-1]*(x-j+1)%Mod)%Mod; } } int s=min(wuke-1,n-r+1); rep(i,0,s+1){ ans=(ans+1ll*f[r-1][wuke-1-i]*g[wuke+1][n-r+1-i]%Mod*fac[i]%Mod)%Mod; } } printf("%d\n",ans); } int main(){ freopen("kangaroo.in","r",stdin); freopen("kangaroo.out","w",stdout); Init(); Solve(); return 0; }
codeforces 442D Adam and Tree
题意:
给出一棵树,最开始只有1个节点。
每个时刻,这棵树会长出一个叶子。
树上每条边都有且只有1种颜色,并且同一种颜色的边都连通。
定义一个点到根的距离为该点到根的路径上的颜色种数。
求每个时刻树上最大距离的最小值。
分析:
考虑每次向上更新dp值,直到更新到根或者不能更新为止。
由树链剖分可知这样做的复杂度是O(nlogn)的。
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int MAXN=1e6+5; int n; int dp[MAXN],p[MAXN]; int mx1[MAXN],mx2[MAXN]; int main(){ freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); scanf("%d",&n); puts("0"); for(int i=2;i<=n;++i){ scanf("%d",p+i); dp[i]=1; int cur=i; while(cur!=1){ int par=p[cur]; if(dp[cur]>mx1[par]){ mx2[par]=mx1[par]; mx1[par]=dp[cur]; } else if(dp[cur]>mx2[par]){ mx2[par]=dp[cur]; } cur=par; int res=max(mx1[cur],mx2[cur]+1); if(res==dp[cur])break; dp[cur]=res; } printf("%d\n",mx1[1]); } return 0; }
codeforces round265 div1 D World of Darkraft - 2
详见zhj的15年集训队论文
#include <math.h> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define rep(i,a,b) for(int i=a;i<b;++i) typedef long double ld; const int MAXN=1000; int n,k,cur; ld dp[2][MAXN]; int main(){ scanf("%d%d",&n,&k); for(int i=n;i;--i){ cur^=1; int B=701; rep(j,1,B){ dp[cur][j]=(dp[cur^1][j]+(1.+j)/2)*j; dp[cur][j]+=(dp[cur^1][j+1]+j); dp[cur][j]/=j+1; dp[cur][j]+=dp[cur^1][j]*(k-1); dp[cur][j]/=k; } } ld ans=dp[cur][1]*k; printf("%.20f\n",(double)ans); return 0; }