天天看點

牛客多校5

B題:

我們隻需要比較 詢問後的數學期望和全部打開盒子的花費輸出最小值就好

因為黑球和白球是等價的,是以有i個黑球和有i個白球的可能性相同

當我們不需要開盒子時:

全為黑(白)球,2/(2 ^ n) = 2^(n-1)

開一個就可以停下來的機率:隻有一個黑(白)球,而且第一次就被我們開到了(1代表黑球,0代表白球)

10000…

01111…

2/(2 ^ n)=2^(1-n)

開兩個停下來的機率2^2/(2 ^ n)

01000…(1個黑)

110000…(2個黑

10111…(1白

0011111…(2白

開三個的機率2^3/(2 ^ n)

00100000…(1黑

10100000…(2黑

01100000…(2黑

11100000…(3黑

我們發現了一個規律,而且每一次的情況枚舉就是如果預言有k個黑球,第k個球一定是在我們開的最後一個箱子取到,而前面可以任意取 是以開黑球 在第i個位置開球後停止的機率為2^(i-1)/(2 ^ n)

白球同理 是以是2^(i-1)*2/(2 ^ n)= 2 ^(i-n)=(1/2) ^ (n-i)這個代表的是第i個位置開哦

#include<bits/stdc++.h>
#define ll long long
#define speed(x) ios::sync_with_stdio(false), cin.tie(x), cout.tie(x)
#define bug(x) cout << #x << " == " << x << '\n';
const ll int MAX_N = 2e5 + 100;
using namespace std;
double cost[MAX_N] = { 0 };
double sum[MAX_N] = { 0 };
int main()
{
    int n;
    double c;
    cin>>n>>c;
    for(int i=1;i<=n;i++)
    {
        scanf("%lf",&cost[i]);
    }
    sort(cost+1,cost+1+n);///肯定是先開便宜箱子啦
    for(int i=1;i<=n;i++)
    {
        sum[i]=cost[i]+sum[i-1];
    }
    double ans = c;
    for(int i=1;i<n;i++)
    {
        ans+=sum[i]*pow(0.5,n-i);
        ///bug(pow(0.5,n-i));
    }
   printf("%.8lf\n",min(ans,sum[n]));
}

           

D題:

題目大意:就是找了兩個等長的子序列字元串 aa,bb

aa<bb

一個字元串大于另一個字元串

兩種情況:首字母a[1]<b[1]

前面幾個字母都相同:然後第i個字母a[i]<b[i]

是以我們隻需要比較每一個字母

a[i]<b[j]的時候

www為計算 a[1~i-1]和b[1-j-1]有多少相等子序列(通過dp求)

ans為a[i+1 ~ a.length()]與b[j+1 ~b.length()]可以組合出多少相同長度子序列

設n=a.length( )-(i+1),m=b.length()-(j+1);

就是C(0,n)*C(0,m)+C(1,n)*C(1,m)+…+C(min(n,m),n)*C((min(n,m),m).

第一種辦法:不妨設n<=m

x從0到n—> C(x,n)*C(x,m)=C(n-x,n)*C(x,m)=C(n,n+m)

通過逆元求組合數就好

第二種辦法:(dp yyds,感謝WWWW同學的好辦法)

我們之前通過dp計算兩個字元串有多少相同子序列

而求n長度的字元串和m長度的字元串可以有多少相同長度的子序列 我們可以想象成後面的字母都是相同的 可以任意取 也可以通過dp來求出

現在:解釋dp[i][j]代表了字元串a的前i個字母的子字元串aa和字元串b的前j個字母的子字元串bb的相同子序列個數

dp[ 0 ][ j ] 相當于aa取得子字元串為空,當bb也為空的時候相同,是以是1,dp[ i ][0]同理!

①sum1=dp[i][j-1]-dp[i-1][j-1]代表了相同子序列中 aa的子序列一定取a[i]和bb的相同子序列的個數

②同理:sum2=dp[i-1][j]-dp[i-1][j-1]代表了相同子序列中 bb的子序列一定取b[j]和aa的相同子序列的個數

③sum3=dp[i-1][j-1]代表了a[i]和b[j]都不取的相同子序列個數

當a[i]!=b[j] dp[i][j]=sum1+sum2+sum3;

當a[i]==b[j] 還可以加上一個sum4代表了 a[i],b[j]都取得相同子序列個數 就是sum3中的每一對相同子序列都在末尾分别加上a[i],b[j],是以sum4 = sum3;

#include<bits/stdc++.h>
#define ll long long
#define speed(x) ios::sync_with_stdio(false), cin.tie(x), cout.tie(x)
#define bug(x) cout << #x << " == " << x << '\n';
const ll int MAX_N = 5e3 + 100;
using namespace std;
ll mod=1e9+7;
ll jc[3*MAX_N] = { 0 };
ll njc[3*MAX_N] = { 0 };
int dp[MAX_N][MAX_N] = { 0 };
ll ccc(int n,int m)
{
    return jc[n+m]*njc[m]%mod*njc[n]%mod;
}
ll epow(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1)ans *= a;
        a *= a;
        a %= mod;
        ans %= mod;
        b >>= 1;
    }
    return ans;
}
int main()
{
    string a,b;
    cin>>a>>b;
    int len1=a.length();
    int len2=b.length();
    a = ' ' + a;
    b = ' ' + b;
    jc[0] = 1;
    for(int i=1;i<=2*MAX_N;i++)
    {
        jc[i] = (ll)i*jc[i-1];
        jc[i] %= mod;
    }
    njc[2*MAX_N-1]=epow(jc[2*MAX_N-1],mod-2)%mod;
    for(int i=2*MAX_N-1;i>=1;i--)
    {
        njc[i-1]=njc[i]*(ll)i%mod;
    }
    ll sum=0;
    for(int i=0;i<=len1;i++)dp[i][0]=1;
    for(int j=1;j<=len2;j++)dp[0][j]=1;
    for(int i=1;i<=len1;i++)
    {
        for(int j=1;j<=len2;j++)
        {
            if(a[i]!=b[j])
            {
                dp[i][j]=(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+mod)%mod;
            }
            else
            {
                 dp[i][j]=(dp[i-1][j]+dp[i][j-1]+mod)%mod;
            }
        }
    }
    for(int i=1; i<=len1; i++)
    {
        for(int j=1; j<=len2; j++)
        {
            if(a[i]<b[j])
            {
                ll ans=ccc(len1-i,len2-j)%mod;
                ll www = dp[i-1][j-1]%mod;
                sum+=www*ans%mod;
                sum%=mod;
            }
        }
    }
    printf("%lld\n",sum%mod);
}