2021牛客多校第五場
阿新 • • 發佈:2021-08-01
B - Boxes(思維)
最多隻需問一次。開箱順序一定是根據代價從小到大開的。當你開箱到某個位置i,i之後的球都是同色,那麼你一定能知道剩餘球的情況,可以提前結束。因此答案就是
\(\sum\limits_{i< n}({\rm P(位置i之後都同色)}\times cost_i)\)。
其中\(cost_i\)代表代價排好序後到\(i\)的字首和。在位置\(i\),有\(\frac{1}{2}\)概率和下一個位置不同色,\(i\)之後的位置有\((\frac{1}{2})^{n-i-1}\)概率與最後一個位置同色,故
\({\rm P(位置i之後都同色)}=\frac{1}{2}\times (\frac{1}{2})^{n-i-1}=(\frac{1}{2})^{n-i}\)
直接遞推求即可。時間複雜度O(n)
最後要與不問的情況取一個最小值。
#include <bits/stdc++.h> #define endl '\n' #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]相等子序列的對數,可得遞推式
- \(dp1[i][j]=dp1[i-1][j]+dp1[i][j-1]-dp[i-1][j-1]\)
- 當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\)
#include <bits/stdc++.h>
#define endl '\n'
#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 '\n'
#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;
}
}