A A A
给定一张 n n n个点的有向图. n ≤ 100 n\le 100 n≤100.
每次随机一个存在的点,然后删除它及其可到达的点.
问期望多少次删除使得图为空.
这道题和最近我做的模拟赛的一道题类似:
一开始有 [ 1 , n ] [1,n] [1,n]的正整数,然后每次随机一个存在的数,删掉所有倍数.
问期望多少次删为空. n ≤ 1 0 10 n\le 10^{10} n≤1010
两者的本质思想是一致的.(不过恶心的地方在于第二题要用
m
i
n
_
25
min\_25
min_25)
考虑一个数
i
i
i删除的时候是随机到自己的概率
p
i
p_i
pi.
那么显然
a
n
s
=
∑
p
i
ans=\sum p_i
ans=∑pi.
因为一次删除序列假设是
a
1
,
a
2
,
.
.
.
,
a
m
a_1,a_2,...,a_m
a1,a2,...,am,那么只有这些被选出来的点记操作次数(
m
m
m),其余的都和操作次数无关,所以我们只要讨论每一个点被选出的概率即可.
更具体地,我们设有 x x x个点能够删除 i i i(包括 i i i自己),那么由它自己删除自己的概率就是 1 x \dfrac 1x x1.
暴力 O ( n 2 ) d f s O(n^2) dfs O(n2)dfs即可.
如果你想练一下
t
a
r
j
a
n
tarjan
tarjan我也不拦你
int n, a[N], vis[N], lst[N], now;
char s[N][N];
void dfs(int x) {
if(lst[x] == now) return;
lst[x]=now; vis[x]++;
FOR(y,n) if(s[x][y] == '1') dfs(y);
}
void solve() {
qr(n);
FOR(i,n) scanf("%s",s[i]+1);
for(now=1;now<=n;now++) dfs(now);
db ans=0;
FOR(i,n) ans += 1.0/vis[i];
printf("%.10lf\n",ans);
}
B B B
给定俩长度为 n n n的字符串 s , t s,t s,t.
每次操作定义为:
找到一个 n ≥ i > 1 n\ge i>1 n≥i>1使得 s i = ′ 1 ′ s_i='1' si=′1′.反转(01互换) s i , s i − 1 s_i,s_{i-1} si,si−1.
问最少的操作次数变为 t t t,或者判定无解.
n ≤ 5 e 5 n\le 5e5 n≤5e5
首先我们来考察一下操作时候的两种情况:
- s i = ′ 1 ′ , s i − 1 = ′ 0 ′ s_i='1',s_{i-1}='0' si=′1′,si−1=′0′.此时就是相当于 s w a p swap swap俩相邻数.
- s i = s i − 1 = ′ 1 ′ s_i=s_{i-1}='1' si=si−1=′1′.此时等价于删除俩个相邻的1.
所以可以得出一个无解的情况, s , t s,t s,t的1个数奇偶性不同.
可以发现
1
1
1只能往前挪,所以我们从前往后扫描,令
t
i
=
1
t_i=1
ti=1贪心匹配最近的
s
j
=
1
(
i
≤
j
)
s_j=1(i\le j)
sj=1(i≤j).
对于一个
s
i
=
1
s_i=1
si=1,如果能和
t
t
t匹配就匹配,否则就自取灭亡(和最近的1配对删除)…
T i p : l o n g l o n g Tip:long~ long Tip:long long
int n;
char a[N], b[N];
void out() {puts("-1"); exit(0);}
void solve() {
qr(n);
scanf("%s%s",a+1,b+1);
ll ans=0;
int f=-1,cnt=0;
FOR(i,n) {
if(b[i] == '1') cnt++,ans -= i;
if(a[i] == '1') {
if(cnt) ans += i,cnt--;
else ans += f*i,f = -f;
}
}
if(cnt || f == 1) out();
pr2(ans);
}
C C C
有 b i b_i bi个写着 a i a_i ai的球.
有无穷个机器人站在一条线上,坐标为 i i i的标号为 i i i.
每次选择一个球,若上面写着 x x x. 如果机器人 x x x存在,那么往前移动一格,如果前面一格有机器人,那么直接把他撞毁.
机器人0是世界的中心,所以你不能破坏它.
为此你可以修改球上的数字.
选择序列可以任意,你需要求出最小的修改次数使得机器人0毫发无损.
可以看出标号小的机器人为弱势群体,容易被撞飞…
同时显然
a
i
≤
b
i
a_i\le b_i
ai≤bi的机器人都可以撞坏
0
0
0.
对于这些危险的机器人,我们首先贪心用他们后面的非危险机器人去撞它.
最后仍然剩余一些机器人
x
1
,
x
2
.
.
.
.
x
m
x_1,x_2....x_m
x1,x2....xm可以撞0.
首先可以发现改变
m
m
m个是可以把这
m
m
m个全部毁掉的,但是这个不够紧.
还有我们可以发现一点: 让危险机器人往前滑
x
x
x个单位的话,要删除这个机器人我们需要
x
x
x个球放在其起点的后一个位置,才能删除它,所以先滑后删是不优秀的.
但是还有一种情况我们没有利用就是:先滑不删.
我们只需对危险机器人挪出
b
i
−
a
i
+
1
b_i-a_i+1
bi−ai+1个,放到后面删除后面的危险机器人即可.
因为前面的所有机器人都可以收到当前机器人的 滑铲.
注意: 被删除的危险机器人也可以用来滑铲.(比赛的时候没想到,错失上分机会,嘤嘤嘤)
int n, a[N], b[N], sta[N], top, t[N];
void solve() {
qr(n);
FOR(i,n) qr(a[i]);
FOR(i,n) qr(b[i]);
FOR(i,n)
if(a[i] <= b[i]) {//dangerous
sta[++top]=i;
t[i]=1;
}
else {
while(top && a[i]-a[sta[top]] <= b[i])
t[sta[top--]]=0;
}
int ans=top,cnt=0;
REP(i,1,n) {
if(a[i] > b[i]) continue;
ans=min(ans,max(b[i]-a[i]+1,cnt));
cnt += t[i];
}
pr2(ans);
}
D D D
求合法的 A A A序列个数,满足:
∑ i = 1 n A i = M , A i ∈ N , 2 A i ≤ A i − 1 + A i + 1 ( i ∈ ( 1 , n ) ) \sum_{i=1}^n A_i=M,A_i\in N,2A_i\le A_{i-1}+A_{i+1}(i\in (1,n)) ∑i=1nAi=M,Ai∈N,2Ai≤Ai−1+Ai+1(i∈(1,n))
n , m ≤ 1 e 5 n,m\le 1e5 n,m≤1e5
背包好题: 考察背包的加入和删除.
首先我们钦定最小值的下标为
m
m
m.(若有多个相同取下标最小)
那么我们可以通过如下形式构造
A
A
A.
- 先令 A = ( C , C , C . . . C ) ( C ≥ 0 ) A=(C,C,C...C)(C\ge 0) A=(C,C,C...C)(C≥0).
- 执行若干次: 找到 i < m i<m i<m,给 A i , A i − 1 , A i − 2 . . . A 1 A_i,A_{i-1},A_{i-2}...A_1 Ai,Ai−1,Ai−2...A1分别加上 1 , 2 , 3... i 1,2,3...i 1,2,3...i.(一定要用一次 i = ( m − 1 ) i=(m-1) i=(m−1),以保证最小性质成立)
- 执行若干次: 找到 i > m i>m i>m,给 A i , A i + 1 . . . . A n A_i,A_{i+1}....A_n Ai,Ai+1....An分别加上 1 , 2 , 3... 1,2,3... 1,2,3....
设
f
(
i
)
=
∑
j
=
1
i
j
f(i)=\sum_{j=1}^i j
f(i)=∑j=1ij.
那么对于固定的
m
m
m,相当于求体积为
M
M
M的完全背包的方案数:
物品大小分别为
n
,
f
(
1
)
,
f
(
2
)
,
.
.
.
f
(
m
−
1
)
(
a
h
e
a
d
)
,
f
(
1
)
,
f
(
2
)
.
.
.
f
(
n
−
m
)
(
b
e
h
i
n
d
)
n,f(1),f(2),...f(m-1)(ahead),f(1),f(2)...f(n-m)(behind)
n,f(1),f(2),...f(m−1)(ahead),f(1),f(2)...f(n−m)(behind).
注意到只有
m
\sqrt m
m种物品有用,所以预处理复杂度为
O
(
m
1.5
)
O(m^{1.5})
O(m1.5)
当
m
m
m移动到
m
+
1
m+1
m+1时,此时完全背包加入一个物品体积为
f
(
m
)
f(m)
f(m),删除一个
f
(
n
−
m
)
f(n-m)
f(n−m).
所以每次更新一下DP数组即可.
注意到
f
(
m
−
1
)
f(m-1)
f(m−1)是钦定的,所以只有
m
\sqrt m
m个位置是合法最小值的下标
m
m
m .
所以总复杂度为
O
(
m
1.5
)
O(m^{1.5})
O(m1.5).
int n, m, F[N];
ll f(ll x) {return x*(x+1)/2;}
void add(ll x) {
for(ll i=x;i<=m;i++)
ad(F[i] ,F[i-x]);
}
void del(ll x) {
for(ll i=m-x;i>=0;i--)
dl(F[i+x],F[i]);
}
void solve() {
qr(n); qr(m); F[0]=1; add(n);
FOR(i,n-1) add(f(i));
ll ans=0;
FOR(i,n) {
if(f(i-1) <= m) ad(ans,F[m-f(i-1)]);
else break;
add(f(i)); del(f(n-i));
}
pr2(ans);
}