Good Bye 2017 D 概率dp E 集合划分贝尔数 F 模拟

Good Bye 2017

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
", 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.

  1. If , then .
  2. If , then
  3. 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
", 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
", ans);

    return 0;
}
View Code
原文地址:https://www.cnblogs.com/sbfhy/p/8167918.html