Good Bye 2017 D 概率dp E 集合划分贝尔数 F 模拟
D. New Year and Arbitrary Arrangement
题意:一个空字符串,有 pa/pa+pb 的概率在串尾加一个 'a',有 pb/pa+pb 的概率在串尾加一个 'b' 。 当序列 "ab" (注是序列,可以不连续) 的数量 >= k 时,停止加入。 问最后得到的串中序列 "ab” 的数量的期望。
tags:概率 dp,思维
dp[i][j] 表示有 j 个"ab"序列,且有 i 个 'a' 时,序列 "ab" 的数量。 很容易看出 dp[i][j] = pa*dp[i+1][j] + pb*dp[i][j+i] 。但仅仅这样推 i 可能会无限大,即 ab 和 abaaaa........ 这样的,可能会一直接下去。
这里看题解说,是可以近似写。 如果 j+i >=n ,那么只要后面再来一个 'b' 就可以停止,我们可以近似认为后面会再加 pa/pb 个 ‘a',然后再加一个 'b'。 即 dp[i][j] = i+j+(pa/pb) 。
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define MP make_pair #define PB push_back #define fi first #define se second typedef long long ll; const int N = 1005, mod = 1e9+7; ll k, pa, pb; ll fpow(ll a, ll b) { ll ans = 1; for( ; b; b>>=1, a=a*a%mod) if(b&1) ans = ans*a%mod; return ans; } ll Inv(ll x) { return fpow(x, mod-2)%mod; } ll dp[N][N]; int main() { scanf("%lld%lld%lld", &k, &pa, &pb); ll sum = pa+pb; pa = pa*Inv(sum)%mod, pb = pb*Inv(sum)%mod; ll pc = pa*Inv(pb)%mod; per(i,k,1) per(j,k,0) { if(j+i >= k) dp[i][j] = (j+i+pc) %mod; else dp[i][j] = (pa*dp[i+1][j]%mod + pb*dp[i][j+i]%mod) %mod; } printf("%lld\n", dp[1][0]); return 0; }
E. New Year and Entity Enumeration
题意:
定义一个 "好集合" :
M = 2m - 1.
A set of integers S is called "good" if the following hold.
- If , then .
- If , then
- All elements of S are less than or equal to M.
给出集合 T,问有多少个好集合 S 。集合里的数都是长度相同的 01 串,且给出的集合 T 里数最多 50个。
tags:贝尔数,没太搞懂。。
每一位分开来算,集合 T 里的数某些位是一样的,就相当于对这些位划分。
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define MP make_pair #define PB push_back #define fi first #define se second typedef long long ll; const int N = 1005, mod = 1e9+7; ll m, n, dp[N][N], Bell[N]; void get_Bell(int mn) { dp[0][0] = 1; rep(i,1,mn) rep(j,1,i) { dp[i][j] = (dp[i-1][j-1] + dp[i-1][j]*j%mod) %mod; (Bell[i] += dp[i][j]) %= mod; } } char s[N]; ll a[N]; int main() { scanf("%lld%lld", &m, &n); get_Bell(m); rep(i,1,n) { scanf("%s", s+1); rep(j,1,m) a[j] = (a[j]<<1) | (s[j]=='1'); } sort(a+1, a+1+m); ll ans = 1, cnt = 0; rep(j,1,m) { ++cnt; if(j==m || a[j]!=a[j+1]) ans = ans*Bell[cnt]%mod, cnt=0; } printf("%lld\n", ans); return 0; }
F. New Year and Rainbow Roads
题意:横坐标上按递增顺序给出 n 个点,每个点可能为 绿、红、蓝 三种颜色。现在要你给这些点之间加边,要满足: 删掉所有红点后,剩下的绿点和蓝点要连通; 删掉所有蓝点后,剩下的绿点和红点要连通。求加的边长度和的最小值。
tags: 恶心模拟
思路很好想,首先红点和蓝点肯定不连,除非没有绿点的情况。
然后按绿点分割开来算就好。即 ....绿........绿......绿...... 这样分割开,对于相邻的绿点,有两种情况都可能是最优的。
1】两绿点不相连,它们之间的所有红点串起来,所有蓝点串起来,再首尾接上两个绿点。
2】两绿点相连,它们之间的红点也是串起来,再连上最接近的绿点,也就是一个环,然后删去最长的边。 蓝点也一样。
说起来很简单,但写起来简直日狗。。。代码能力还是太弱了
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define MP make_pair #define PB push_back #define fi first #define se second typedef long long ll; const int N = 300005; const ll inf = 1e17; ll n, p[N], f[3][N], ans; char c[N]; ll veg[N], cnt1; int main() { scanf("%lld", &n); ll t[3]; t[0]=t[1]=t[2]=-inf; int cnt=0; rep(i,1,n) { scanf("%lld %c", &p[i], &c[i]); if(c[i]=='G') t[0]=p[i], ++cnt; else if(c[i]=='R') t[1]=p[i]; else t[2]=p[i]; rep(j,0,2) f[j][i] = p[i]-t[j]; } t[0]=t[1]=t[2]=inf; per(i,n,1) { if(c[i]=='G') t[0]=p[i]; else if(c[i]=='R') t[1]=p[i]; else t[2]=p[i]; rep(j,0,2) f[j][i] = min(f[j][i], t[j]-p[i]); } if(cnt==0) { t[1]=t[2]=-inf; ll mi = inf; rep(i,1,n) { if(c[i]=='R') { if(t[1]!=-inf) ans += p[i]-t[1]; t[1] = p[i]; mi = min(mi, f[2][i]); } else { if(t[2]!=-inf) ans += p[i]-t[2]; t[2] = p[i]; mi = min(mi, f[1][i]); } } } else { ll ans1, ans2; rep(i,1,n) if(c[i]=='G') veg[++cnt1]=i; t[1]=t[2]=p[veg[1]]; per(i, veg[1]-1, 1) { if(c[i]=='R') ans+=t[1]-p[i], t[1]=p[i]; else ans+=t[2]-p[i], t[2]=p[i]; } t[1]=t[2]=p[veg[cnt]]; rep(i, veg[cnt]+1, n) { if(c[i]=='R') ans+=p[i]-t[1], t[1]=p[i]; else ans+=p[i]-t[2], t[2]=p[i]; } ll mx1, mx2, tmp1, tmp2; rep(i,2,cnt) { ans1=ans2=tmp1=tmp2=0; mx1=mx2=-inf; t[1]=t[2]=p[veg[i-1]]; rep(j, veg[i-1]+1, veg[i]-1) { if(c[j]=='R') tmp1+=p[j]-t[1], t[1]=p[j]; else tmp2+=p[j]-t[2], t[2]=p[j]; } t[1]=t[2]=p[veg[i]]; per(j, veg[i]-1, veg[i-1]+1) { if(c[j]=='R' && t[1]==p[veg[i]]) tmp1+=t[1]-p[j], t[1]=p[j]; else if(c[j]=='B' && t[2]==p[veg[i]]) tmp2+=t[2]-p[j], t[2]=p[j]; } if(tmp1==0 || tmp2==0) ans1=inf; else ans1=tmp1+tmp2; t[1]=t[2]=p[veg[i-1]]; rep(j, veg[i-1]+1, veg[i]-1) { if(c[j]=='R') { if(t[1]==p[veg[i-1]]) ans2+=f[0][j], mx1=max(mx1,f[0][j]); else ans2+=p[j]-t[1], mx1=max(mx1, p[j]-t[1]); t[1] = p[j]; } else { if(t[2]==p[veg[i-1]]) ans2+=f[0][j], mx2=max(mx2, f[0][j]); else ans2+=p[j]-t[2], mx2=max(mx2, p[j]-t[2]); t[2] = p[j]; } } t[1]=t[2]=p[veg[i]]; per(j, veg[i]-1, veg[i-1]+1) { if(c[j]=='R' && t[1]==p[veg[i]]) ans2+=f[0][j], mx1=max(mx1,f[0][j]), t[1]=p[j]; else if(c[j]=='B' && t[2]==p[veg[i]]) ans2+=f[0][j], mx2=max(mx2,f[0][j]), t[2]=p[j]; } if(mx1!=-inf) ans2-=mx1; if(mx2!=-inf) ans2-=mx2; ans2 += p[veg[i]]-p[veg[i-1]]; ans += min(ans1, ans2); } } printf("%lld\n", ans); return 0; }