T1 幸运数字 ( 100 p t s 100pts 100pts )
题目
思路
4
4
4 的倍数一定满足最后两位能被
4
4
4 整除,只要枚举最后一位的位置,判断前一位和当前位组成的数能否
被
4
4
4 整除,如果能那么左端点可以任选。注意要额外加上0,4,8的个数,即每一位是否能被
4
4
4 整除。
code
#include<bits/stdc++.h>
#pragma GCC optimize(3)
#pragma GCC optimize(2)
#define int long long
using namespace std;
const int N=3e5+10;
string s;int ans,n,a[N];
signed main(void){
cin>>s;
n=s.length();
for(int i=0;i<n;++i){
a[i]=s[i]^48;
}
for(int i=0;i<n;++i){
if (!(a[i]&3)){
++ans;
}
}
for(int i=1;i<n;++i){
if(!((a[i-1]*10+a[i])&3)){
ans+=i;//如果这个子串是4的倍数,那加上前面的东西也是
}
}
printf("%lld\n",ans);
return 0;
}
T2 密码( 0 p t s 0pts 0pts )
题目
思路
最重要的事是判断 a a a 大还是 b b b 大。从前往后枚举每一位,如果当前之前的某一位能分出大小,则小的数尽可能填 9 9 9,大的数尽可能填 0 0 0。
否则如果当前一位上两个数中有一个是 ?
另一个是
x
x
x,尝试在这个位置
填
x
x
x,
x
+
1
x + 1
x+1,
x
−
1
x − 1
x−1。如果都是 ?
,则试着填
(
0
,
0
)
,
(
0
,
1
)
,
(
1
,
0
)
(0, 0),(0, 1),(1, 0)
(0,0),(0,1),(1,0)。搜索一下即可。
T3 小X和他的朋友们( 20 p t s 20pts 20pts )
题目
思路
20
p
t
s
20pts
20pts
考虑
n
=
1
n=1
n=1 时,因为只有他1个人,所以输出
1
1
1。
且当
k
≥
m
k \ge m
k≥m 时,第一个人可以全部拿完,输出
1
1
1。
当
n
=
2
n=2
n=2 时,可以推得为
m
m%(k+1)
m。
100
p
t
s
100pts
100pts
首先考虑每个人选定伙伴的策略:一定是在他后面的所有人都要选。因为我们不要求知道最后能剩下多
少钱,对于一个人
i
i
i,
j
>
k
j > k
j>k 如果
i
−
j
i − j
i−j 选
i
i
i 做伙伴而
i
−
k
i − k
i−k 没选
i
i
i 做伙伴,
i
i
i 会让
i
−
j
i − j
i−j 赢,而如果
i
−
k
i − k
i−k 也选
i
i
i
做伙伴,
i
i
i 会让
i
−
k
i − k
i−k 赢。(因为
i
−
k
i − k
i−k 给他的钱更多)。所以尽可能的把友情奖分出去,才能最大可能获
得胜利。(虽然不一定是必要的)
然后考虑每个人会让谁赢:
- 优先让自己赢。
- 自己不能赢的情况下优先让在他前面的人赢(可以获得友情奖),且距离离他尽可能地近。
- 如果 2 2 2 也不可能,会让编号较大的人赢。(只有基础奖金)
可以发现,每个人让别人赢的优先级都是一个逆时针的环。
考 虑 求 解 最 后 谁 能 赢,
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表 示 当 前 轮 到
i
i
i 取 石 子 , 剩 余
j
j
j 个 石 子 , 最 后 谁 能
赢,
f
[
i
]
[
j
]
=
(
f
[
i
+
1
]
[
j
−
1
]
−
>
f
[
i
+
1
]
[
j
−
k
]
f[i][j] = (f[i + 1][j − 1]− > f[i + 1][j − k]
f[i][j]=(f[i+1][j−1]−>f[i+1][j−k] 中对
i
i
i 最优的那一个)如果打表可以发现,
d
p
dp
dp 值对于
j
j
j
在每
n
+
k
−
1
n + k − 1
n+k−1 层就会出现循环,所以把
m
m
m 取模后直接找到对应层数的
f
[
1
]
[
i
]
f[1][i]
f[1][i] 即可。另外
f
[
1
]
[
i
]
f[1][i]
f[1][i] 也可以
在
O
(
1
)
O(1)
O(1) 的时间求出。
复杂度
O
(
T
)
O(T)
O(T)。
T4 树上询问
题目
思路
询问其实就是求带权重心。
结论:深度最小的带权重心的子树权值和一定严格大于所有点权值和的一半。
证明:如果比满足这个条件,把这个点的父亲设成答案会更优(因为离更多的点更近了,这里不妨把权
值看成是多个权值为
1
1
1 的点)
任意取这棵树的一个 dfs 序,按照 dfs 序把每一个点编号写下来形成一个序列,其中节点
i
i
i 连续写
a
i
a_i
ai
次。那么因为深度最小带权重心的子树大小严格大于一半,那么在序列中,这个点的子树所表示区间的
长度也一定严格大于一半,所以序列最中间的数一定在答案点的子树内。
那么我们可以用 树剖 + 线段树 维护,找最中间的点可以用线段树二分找出(因为线段树上编号本来就是
一个 dfs 序),那么答案一定是找到的点的一个祖先,倍增寻找即可。
尾语:
历史落在赢家之手
至少我们拥有传说
谁说败者无法不朽
拳头只能让人低头
念头却能让人抬头
抬头去看去爱去追
你心中的梦