2021牛客多校第五场

来源

B - Boxes(思维)

最多只需问一次。开箱顺序一定是根据代价从小到大开的。当你开箱到某个位置i,i之后的球都是同色,那么你一定能知道剩余球的情况,可以提前结束。因此答案就是

(sumlimits_{i< n}({ m P(位置i之后都同色)} imes cost_i))​​​。

其中(cost_i)​代表代价排好序后到(i)​的前缀和。在位置(i)​,有(frac{1}{2})​概率和下一个位置不同色,(i)之后的位置有((frac{1}{2})^{n-i-1})概率与最后一个位置同色,故

({ m P(位置i之后都同色)}=frac{1}{2} imes (frac{1}{2})^{n-i-1}=(frac{1}{2})^{n-i})

直接递推求即可。时间复杂度O(n)

最后要与不问的情况取一个最小值。

#include <bits/stdc++.h>

#define endl '
'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N) 
typedef long long ll;

using namespace std;
/*-----------------------------------------------------------------*/

ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f

const int N = 1e5 + 10;
const int M = 1e9 + 7;
const double eps = 1e-5;

double cost[N];
double dp[N];

int main() {
    IOS;
    int n;
    double c;
    cin >> n >> c;
    double p = 0.5;
    for(int i = 1; i <= n; i++) {
        cin >> cost[i];
    }
    sort(cost + 1, cost + 1 + n);
    for(int i = 1; i <= n; i++) {
        cost[i] += cost[i - 1];
    }
    double ans = 0;
    for(int i = n - 1; i >= 1; i--) {
        ans += p * cost[i];
        p *= 0.5;
    }
    cout << seteps(10) << min(cost[n], ans + c) << endl;
}

D - Double String(dp)

(dp1[i][j])代表A[1...i]和B[1...j]相等子序列的对数,可得递推式

  1. (dp1[i][j]=dp1[i-1][j]+dp1[i][j-1]-dp[i-1][j-1])
  2. 当A[i]==B[i]时,额外有(dp1[i][j]=1+dp[i-1][j-1])

(dp2[i][j])代表从{1, 2, ..., i} 和 {1, 2, ..., j}中取出长度相同的序列的对数,等价于所有字符相等的(dp1),即

(dp2[i][j]=1+dp2[i-1][j]+dp2[i][j-1])

枚举(i)(j),当(A[i]<B[j])时,贡献为((dp[i-1][j-1]+1) imes(dp[n-i][m-j]+1))

#include <bits/stdc++.h>

#define endl '
'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N) 
typedef long long ll;

using namespace std;
/*-----------------------------------------------------------------*/

ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f

const int N = 5e3 + 10;
const int M = 1e9 + 7;
const double eps = 1e-5;

char s1[N], s2[N];
int dp1[N][N];
int dp2[N][N];

int main() {
    IOS;
    cin >> s1 + 1 >> s2 + 1;
    int n, m;
    n = strlen(s1 + 1), m = strlen(s2 + 1);
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            if(s1[i] == s2[j]) {
                dp1[i][j]++;
                dp1[i][j] = (dp1[i][j] + dp1[i - 1][j - 1]) % M;
            }
            dp2[i][j]++;

            dp1[i][j] = (dp1[i][j] + dp1[i][j - 1]) % M;
            dp1[i][j] = (dp1[i][j] + dp1[i - 1][j]) % M;
            dp1[i][j] = (dp1[i][j] - dp1[i - 1][j - 1]) % M;

            dp2[i][j] = (dp2[i][j] + dp2[i][j - 1]) % M;
            dp2[i][j] = (dp2[i][j] + dp2[i - 1][j]) % M;
        }
    }
    // cout << dp1[n][m] << endl;

    ll ans = 0;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            if(s1[i] < s2[j]) {
                ans = (ans + 1ll * (dp1[i - 1][j - 1] + 1) * (dp2[n - i][m - j] + 1) % M) % M;
            }
        }
    }
    cout << (ans % M + M) % M << endl;
}

King of Range

用双端队列维护最大值和最小值,每次插入一个数后从两个队列的队头弹出差值大于k的位置(因为差值递增),累计统计答案即可。

#include <bits/stdc++.h>

#define endl '
'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N) 
typedef long long ll;

using namespace std;
/*-----------------------------------------------------------------*/

ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f

const int N = 3e5 + 10;
const double eps = 1e-5;

typedef pair<int, int> PII;
int arr[N];
PII mx[N], mi[N];
int s1, t1, s2, t2;

int main() {
    IOS;
    int n, m;
    cin >> n >> m;
    for(int i = 1; i <= n; i++) {
        cin >> arr[i];
    }
    while(m--) {
        s1 = t1 = 0;
        s2 = t2 = 0;
        int k;
        cin >> k;
        ll ans = 0;
        int cnt = 0;
        for(int i = 1; i <= n; i++) {
            int cnt1 = 1, cnt2 = 1;
            while(s1 != t1 && mx[t1 - 1].first <= arr[i]) cnt1 += mx[t1 - 1].second, t1--;
            while(s2 != t2 && mi[t2 - 1].first >= arr[i]) cnt2 += mi[t2 - 1].second, t2--;
            mx[t1++] = {arr[i], cnt1};
            mi[t2++] = {arr[i], cnt2};
            while(s1 != t1 && s2 != t2 && mx[s1].first - mi[s2].first > k) {
                if(mx[s1].second > mi[s2].second) {
                    mx[s1].second -= mi[s2].second;
                    cnt += mi[s2].second;
                    s2++;
                } else {
                    mi[s2].second -= mx[s1].second;
                    cnt += mx[s1].second;
                    s1++;
                    if(!mi[s2].second) s2++;
                }
            }
            ans += cnt;
        }
        cout << ans << endl;
    }
}
原文地址:https://www.cnblogs.com/limil/p/15086795.html