B.Boxes
-
题意 给你
n
n
n个装有白球或者黑球的盒子,其中盒子里是白球的概率为
1
2
\frac{1}{2}
21?。打开第
i
i
i个盒子的代价是
w
i
w_i
wi?,在你没有打开盒子之前你无法知道盒子中的球的颜色。而你最多有一次机会可以使用
C
C
C代价来知道剩余的盒子里面还有多少黑球。问你最小成本的数学期望是多少? -
解题思路 我们如果不使用
C
C
C,我们无法知道盒子中黑球白球的分布,那么只能打开所有的盒子,代价为
∑
w
i
\sum w_i
∑wi?。那么如果我们使用了
C
C
C,我们就可以预知我们要开多少个黑球盒子,这样就相当于
01
01
01序列贪心开即可。 -
AC代码
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl;
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
double ans,sum;
int n;
double c,w[N];
void solve(){
sort(w + 1, w + 1 + n);
double f = 1.0;
for(int i = n; i; -- i){
ans += (1.0 - f) * w[i];
f /= 2;
}
printf("%.8lf\n", min(sum,c + ans));
}
int main(){
scanf("%d%lf", &n, &c);
for(int i = 1; i <= n; ++ i){
scanf("%lf", &w[i]);
sum += w[i];
}
solve();
return 0;
}
D.Double Strings
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl;
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 5e3 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int fac[N << 1],inv[N << 1];
int dp[N][N];
char a[N],b[N];
int qsm(int n,int q){
int ans = 1;
while(q){
if(q & 1)ans = 1LL * ans * n % P;
n = 1LL * n * n % P;
q >>= 1;
}
return ans;
}
void init(){
fac[0] = fac[1] = 1;
for(int i = 2; i < N * 2; ++ i){
fac[i] = 1LL * fac[i - 1] * i % P;
}
inv[N * 2 - 1] = qsm(fac[N * 2 - 1],P - 2);
for(int i = N * 2 - 2; i >= 0; -- i){
inv[i] = 1LL * inv[i + 1] * (i + 1) % P;
}
}
int C(int n,int m){
return 1LL * fac[n] * inv[m] % P * inv[n - m] % P;
}
void solve(){
int n = strlen(a + 1), m = strlen(b + 1);
for(int i = 0; i <= n; ++ i)dp[i][0] = 1;
for(int j = 0; j <= m; ++ j)dp[0][j] = 1;
int ans = 0;
for(int i = 1; i <= n; ++ i){
for(int j = 1; j <= m; ++ j){
dp[i][j] = ((dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1]) % P + P) % P;
if(a[i] == b[j])dp[i][j] = (dp[i][j] + dp[i - 1][j - 1]) % P;
else if(a[i] < b[j]){
ans = (ans + 1LL * dp[i - 1][j - 1] * C(n - i + m - j, n - i) % P) % P;
}
}
}
printf("%d\n", (ans + P) % P);
}
int main(){
init();
scanf("%s%s", a + 1, b + 1);
solve();
return 0;
}
H.Holding Two
-
题意 需要你构造一个矩阵,使得不存在
3
3
3个独立的点
a
i
1
j
1
,
a
i
2
j
2
,
a
i
3
j
3
a_{i_1j_1},a_{i_2j_2},a_{i_3j_3}
ai1?j1??,ai2?j2??,ai3?j3??满足
a
i
1
j
1
=
a
i
2
j
2
=
a
i
3
j
3
a_{i_1j_1}=a_{i_2j_2}=a_{i_3j_3}
ai1?j1??=ai2?j2??=ai3?j3??,
∣
i
1
?
i
2
∣
≤
1
,
∣
i
2
?
i
3
∣
≤
1
,
∣
j
1
?
j
2
∣
≤
1
,
∣
j
2
?
j
3
∣
≤
1
|i_1-i_2|\leq 1,|i_2-i_3|\leq 1,|j_1-j_2|\leq 1,|j_2-j_3|\leq 1
∣i1??i2?∣≤1,∣i2??i3?∣≤1,∣j1??j2?∣≤1,∣j2??j3?∣≤1。 -
解题思路 构造可得
001100...
110011...
001100..
.
.
.
001100...\\110011...\\001100..\\...
001100...110011...001100..... 这种方案一定可行。 -
AC代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1000 + 5;
const int P = 1e9+7;
int n,m;
void solve(){
for(int i = 1; i <= n; ++ i){
int op;
if(i & 1)op = 1;
else op = 0;
for(int j = 1; j <= m; ++ j){
cout << char(op + '0');
if(j % 2 == 0){
op ^= 1;
}
}
cout << endl;
}
}
int main(){
cin >> n >> m;
solve();
return 0;
}
J.Jewels
-
题意 有
n
n
n颗宝石,其坐标为
(
x
i
,
y
i
,
z
i
)
(x_i,y_i,z_i)
(xi?,yi?,zi?),同时有一个参数
v
i
v_i
vi?。你的位置在
(
0
,
0
,
0
)
(0,0,0)
(0,0,0),当你需要取宝石
i
i
i时,设当前时刻为
t
t
t,那么代价为
x
i
2
+
y
i
2
+
(
z
i
+
t
v
i
)
2
x_i^2+y_i^2+(z_i+tv_i)^2
xi2?+yi2?+(zi?+tvi?)2。求取完所有宝石的代价,时刻从
0
0
0开始,一刻只能取一个宝石。 -
解题思路 我们知道,宝石一定会在
n
?
1
n-1
n?1时刻内取完,即每个时刻对应一颗宝石,所以我们可以将宝石和时刻看成是二部图,其权值则为对应时刻的代价,那么实际上我们需要求的就是最小权匹配。直接使用
K
M
KM
KM算法。注:网上好多假的
K
M
KM
KM算法,即超时代码,连
k
b
kb
kb模板的也超时了,还好现场学习了一波别人的玄学KM算法。 -
AC代码
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl;
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 300 + 10;
const int P = 1e9 + 7;
const ll INF = 1e16;
ll g[N][N],lx[N],ly[N];
int n,linker[N];
bool visX[N],visY[N];
ll slack[N];
int last[N];
void bfs(int x){
int y = 0,y1;
for(int i = 1; i <= n; ++ i){
last[i] = 0,slack[i] = INF;
}
linker[y] = x;
do{
int i = linker[y];
ll d = INF;
visY[y] = true;
for(int j = 1; j <= n; ++ j){
if(!visY[j]){
if(slack[j] > lx[i] + ly[j] - g[i][j]){
slack[j] = lx[i] + ly[j] - g[i][j];
last[j] = y;
}
if(slack[j] < d){
d = slack[j];
y1 = j;
}
}
}
for(int j = 0; j <= n; ++ j){
if(visY[j]){
lx[linker[j]] -= d,ly[j] += d;
}
else{
slack[j] -= d;
}
}
y = y1;
}while(linker[y]);
while(y) linker[y] = linker[last[y]],y = last[y];
}
ll KM(){
for(int i = 0; i <= n; ++ i){
linker[i] = lx[i] = ly[i] = 0;
}
for(int i = 1; i <= n; ++ i){
for(int j = 0; j <= n; ++ j)visY[j] = false;
bfs(i);
}
ll ans = 0;
for(int j = 1; j <= n; ++ j){
if(linker[j])ans += g[linker[j]][j];
}
return ans;
}
void solve(){
printf("%lld\n", -KM());
}
int main(){
scanf("%d", &n);
int x,y,z,v;
for(int i = 1; i <= n; ++ i){
scanf("%d%d%d%d", &x, &y, &z, &v);
for(int j = 0; j < n; ++ j){
g[i][j + 1] = -(x * x + y * y + 1LL * (z + j * v) * (z + j * v));
}
}
solve();
return 0;
}
K.King of Range
-
题意 给你一个序列
a
a
a,有
m
m
m次询问,每次询问给出一个
k
k
k,需要你计算有多少区间
[
l
,
r
]
[l,r]
[l,r]满足其中区间的
m
a
x
?
m
i
n
>
k
max-min>k
max?min>k。 -
解题思路 首先,我们需要知道,如果我们找到一个右端点为满足极差大于
k
k
k的最小的
r
r
r,那么说明有
r
r
r个区间是符合的,我们可以利用两个单调队列来维护最大值和最小值,这样就可以得到极差了,然后每次弹出队列元素知道极差小于等于
k
k
k,这样即可求解出
r
r
r了。 -
AC代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;
int n,m,k,a[N];
int q1[N],q2[N];
int s1,e1,s2,e2;
ll ans;
void solve(){
while(m -- ){
scanf("%d", &k);
ans = 0;
s1 = s2 = 1,e1 = e2 = 0;
int r = 0;
for(int i = 1; i <= n; ++ i){
while(s1 <= e1 && a[q1[e1]] >= a[i])e1 --;
while(s2 <= e2 && a[q2[e2]] <= a[i])e2 --;
q1[++e1] = i, q2[++e2] = i;
while(s1 <= e1 && s2 <= e2 && a[q2[s2]] - a[q1[s1]] > k){
if(s1 <= e1 && (s2 > e2 || q1[s1] < q2[s2])){
r = q1[s1 ++];
}
else{
r = q2[s2 ++];
}
}
ans += r;
}
printf("%lld\n", ans);
}
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
}
solve();
return 0;
}
|