2021牛客暑期多校训练营5
B-Boxes
思路
如果问,在最开头问一次是最优的,多问没有意义;但是不问也可能是最优的情况。所以对问的情况与不问的情况分别求期望,取其最小值即可。
对于问的情况,期望为: E = ∑ i = 1 n 2 − n − i − 1 ∗ ∑ j = 1 i ( w i ) E = \sum_{i = 1}^{n}2^{-n - i - 1} * \sum_{j = 1}^i(w_i) E=∑i=1n2−n−i−1∗∑j=1i(wi),对于不问的情况,期望为: ∑ i = 1 n w i \sum_{i = 1}^nw_i ∑i=1nwi 。
比赛的时候被卡了精度,不小心比较的时候把int和double比较了,一直WA……
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pai;
typedef pair<ll, ll> pal;
typedef pair<double, double> pad;
const ll INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const ll maxn = 1e5 + 5;
const double eps = 1e-7;
const double PI = acos(-1);
inline void std_quick_io() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
int main () {
int n;
double c;
scanf("%d%lf", &n, &c);
vector<double> w(n + 1);
vector<double> suf(n + 2, 0);
w[0] = 0;
double h = 0;
for(int i = 1; i <= n; i++) {
scanf("%lf", &w[i]);
h += w[i];
}
for (int i = n; i >= 0; i--)
suf[i] = suf[i + 1] + w[i];
if(n == 1) {
printf("%.10f\n", min(w[1], c));
return 0;
}
sort(w.begin() + 1, w.end());
vector<double> p(n + 2, 0);
p[0] = 1.0;
for (int i = 1; i <= n; i++) p[i] = p[i - 1] * 0.5;
double sum = 0;
double ans = c;
for (int i = 1; i < n; i++) {
sum += w[i];
ans += p[n - i] * sum;
}
printf("%.10f\n", min(h, ans));
return 0;
}
D-Double Strings
思路
先统计一遍以
i
,
j
i, j
i,j 结尾的字数组中有多少完全匹配的前缀,递推式为
d
p
1
i
,
j
=
{
d
p
1
i
−
1
,
j
+
d
p
1
i
,
j
−
1
−
d
p
1
i
−
1
,
j
−
1
,
a
i
≠
b
j
d
p
1
i
−
1
,
j
+
d
p
1
i
,
j
−
1
,
a
i
=
b
j
dp1_{i, j} = \left\{ \begin{aligned} dp1_{i - 1, j} + dp1_{i, j - 1} - dp1_{i - 1, j - 1} \ , \ a_i ≠ b_j \\ dp1_{i - 1, j} + dp1_{i, j - 1} \ , \ a_i = b_j \end{aligned} \right.
dp1i,j={dp1i−1,j+dp1i,j−1−dp1i−1,j−1 , ai=bjdp1i−1,j+dp1i,j−1 , ai=bj
再推一遍以
i
,
j
i, j
i,j 结尾的字数组中有多少复合要求的字符串,递推式为
d
p
2
i
,
j
=
{
d
p
2
i
−
1
,
j
+
d
p
2
i
,
j
−
1
,
a
i
≥
b
j
d
p
2
i
−
1
,
j
+
d
p
2
i
,
j
−
1
+
d
p
1
i
−
1
,
j
−
1
,
a
i
<
b
j
dp2_{i, j} = \left\{ \begin{aligned} dp2_{i - 1, j} + dp2_{i, j - 1} \ , \ a_i \geq b_j \\ dp2_{i - 1, j} + dp2_{i, j - 1} + dp1_{i - 1, j - 1} \ , \ a_i < b_j \end{aligned} \right.
dp2i,j={dp2i−1,j+dp2i,j−1 , ai≥bjdp2i−1,j+dp2i,j−1+dp1i−1,j−1 , ai<bj
代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 5e3 + 10;
int dp1[N][N];
int dp2[N][N];
string a;
string b;
int main()
{
int n, m;
cin >> a;
cin >> b;
n = a.size();
m = b.size();
a = " " + a;
b = " " + b;
for(int i = 0; i <= n; i++)
dp1[i][0] = 1;
for(int i = 0; i <= m; i++)
dp1[0][i] = 1;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
dp1[i][j] = ((dp1[i - 1][j] + dp1[i][j - 1]) % mod - dp1[i - 1][j - 1] + mod) % mod;
if(a[i] == b[j])
dp1[i][j] = (dp1[i][j] + dp1[i - 1][j - 1]) % mod;
}
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
dp2[i][j] = (dp2[i - 1][j] + dp2[i][j - 1]) % mod;
if(a[i] < b[j])
dp2[i][j] = (dp2[i][j] + dp1[i - 1][j - 1]) % mod;
}
}
cout << dp2[n][m] << endl;
return 0;
}
G-Greater Integer, Better LCM
H-Holding Two
思路
签到题来了,横向每次输出两个0两个1,竖向01交替即可,比如:
001100110011
110011001100
代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n, m;
cin >> n >> m;
for(int i = 0; i < n; i++)
{
if(i & 1)
{
for(int j = 0, cnt = 0; j < m; j += 2, cnt++)
{
//cout << j <<endl;
if(cnt & 1)
{
if(j + 2 > m)
cout << '0';
else
cout << "00";
}
else
{
if(j + 2 > m)
cout << '1';
else
cout << "11";
}
}
cout << endl;
}
else
{
for(int j = 0, cnt = 0; j < m; j += 2, cnt++)
{
//cout << j <<endl;
if(cnt & 1)
{
if(j + 2 > m)
cout << '1';
else
cout << "11";
}
else
{
if(j + 2 > m)
cout << '0';
else
cout << "00";
}
}
cout << endl;
}
}
}
J-Jewels
K-King of Range
思路
用ST表维护区间极大/小值,对于每次的查询k,双指针去找对于每个 l l l 最小的 r r r ,使得 r a n g e ( l , r ) > k range(l, r) > k range(l,r)>k 。这里有个性质, r a n g e ( l , r ) range(l, r) range(l,r) 随着区间长度 ( r − l ) (r - l) (r−l) 的增加是不会下降的,这也是这题可以用双指针的原因。但是不能用任何 n log n n\log n nlogn 的算法,会t,所以线段树不行,最后双指针也不能用二分代替(亲身实验过不行)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int max_st[N][40] = {0};
int min_st[N][40] = {0};
int lg[N] = {0};
int a[N];
void init(int n)
{
for(int i = 1; i <= n; ++i)
max_st[i][0] = min_st[i][0] = a[i];
for (int j = 1; (1 << j) <= n; ++j)
for (int i = 1; i + (1 << (j - 1)) <= n; ++i)
max_st[i][j] = max(max_st[i][j - 1], max_st[i + (1 << (j - 1))][j - 1]),
min_st[i][j] = min(min_st[i][j - 1], min_st[i + (1 << (j - 1))][j - 1]);
for (int i = 2; i <= n; ++i)
lg[i] = lg[i / 2] + 1;
}
int maxST(int l, int r)
{
if (l > r) //这个看情况返回
return 0;
int s = lg[r - l + 1];
return max(max_st[l][s], max_st[r - (1 << s) + 1][s]);
}
int minST(int l, int r)
{
if (l > r) //这个看情况返回
return 0;
int s = lg[r - l + 1];
return min(min_st[l][s], min_st[r - (1 << s) + 1][s]);
}
int query(int l, int r)
{
return maxST(l, r) - minST(l, r);
}
int main()
{
int n, m;
scanf("%d %d",&n,&m);
for(int i = 1; i <= n; ++i)
{
scanf("%d",&a[i]);
}
init(n);
for(int i = 0; i < m; i++)
{
int k;
scanf("%d", &k);
int r = 1;
ll ans = 0;
for(int l = 1; l <= n; l++)
{
while(r <= n && query(l, r) <= k)
r++;
ans += n - r + 1;
//cout << l << ' ' << r << ' ' << n << endl;
if(r == n + 1)
break;
}
printf("%lld\n", ans);
}
return 0;
}