A 感觉怪怪的神秘题
B 巨大思维检测题
C 找不是1的个数
D 暴力模拟,复杂度是对的
E 排序之后前缀和或者双指针
F 找前面出现的有1的位置分类讨论一下
G bitset的树形背包
H 幽默的智力检测题
A:984
B :179780307
对于任意
a
i
×
a
j
≤
i
×
j
+
2025
a_i \times a_j \leq i \times j + 2025
ai×aj≤i×j+2025
求方案数
答案对
1
0
9
+
7
10^9 + 7
109+7 取模
n
<
=
2025
n <= 2025
n<=2025
思考
考虑
2025
2025
2025 应该在哪
如果
2025
2025
2025 在
x
x
x 位置
那么 要求
x
2
+
2025
≥
2025
×
2025
x ^2 + 2025 \ge 2025 \times 2025
x2+2025≥2025×2025
那么
x
2
≥
2024
×
2025
x^2 \ge 2024 \times 2025
x2≥2024×2025
可以发现
x
x
x 必须等于
2025
2025
2025
反推
2024
2024
2024 应该在哪
假设在
y
y
y
那么
2025
×
2024
≤
2025
×
y
+
2025
2025 \times 2024 \le 2025 \times y + 2025
2025×2024≤2025×y+2025
那么
2025
×
2024
≤
2025
×
(
y
+
1
)
2025 \times 2024 \leq 2025 \times (y + 1)
2025×2024≤2025×(y+1)
由于
y
y
y 不能等于
2025
2025
2025
所以可得
y
=
2024
y = 2024
y=2024 或者
2023
2023
2023
同时有
2024
×
2024
≤
y
×
y
+
2025
2024 \times 2024 \le y \times y + 2025
2024×2024≤y×y+2025
由于
2023
×
2024
+
2
<
2024
∗
2024
2023 \times 2024 + 2 < 2024 * 2024
2023×2024+2<2024∗2024
所以
y
y
y 只能在
2024
2024
2024
顺推
假设
2023
2023
2023 在
z
z
z 号位置
那么有式子
2025
×
2023
≤
2025
×
z
+
2025
2025 \times 2023 \le 2025 \times z + 2025
2025×2023≤2025×z+2025
2024
×
2023
≤
2024
×
z
+
2025
2024 \times 2023 \le 2024 \times z + 2025
2024×2023≤2024×z+2025
2025
×
2023
≤
2025
×
(
z
+
1
)
2025 \times 2023 \le 2025 \times (z + 1)
2025×2023≤2025×(z+1)
可以发现
z
z
z 只能选择
2023
2023
2023 或者
2022
2022
2022
数学归纳法
对于数字 x 在位置 y
2025
×
x
≤
2025
×
y
+
2025
2025 \times x \le 2025 \times y + 2025
2025×x≤2025×y+2025
2025
×
x
≤
2025
×
(
y
+
1
)
2025 \times x \le 2025 \times (y + 1)
2025×x≤2025×(y+1)
即有
x
≤
(
y
+
1
)
x \le (y + 1)
x≤(y+1)
可以推导出 必须放在
x
−
1
x - 1
x−1之后
但上述推导可以发现对于后几位数字是存在一个问题的
即特别大的几个数字的位置是固定在某个位置的
仅当数字变小到达一定程度之后会导致
+
2025
+ 2025
+2025 使得前面的位置可以发生变化
那么可以尝试枚举
推导一下
假设
1
1
1 号位在
1
1
1,或者
2
2
2
如果
1
1
1 在
2
2
2
2
2
2 要么在
1
1
1,要么在
3
3
3
如果
2
2
2 在
3
3
3,那么
3
3
3 无法放到
1
1
1
所以
2
2
2 必须放在
1
1
1
所以固定枚举顺序为
1
2
1\ 2
1 2 或者
2
1
2\ 1
2 1
考虑
3
4
3\ 4
3 4 应该也会存在这种情况
所以应该是一个
d
p
N
dp_N
dpN 的式子
来维护上面所设置的选择要求
考虑
d
p
dp
dp 的后效性问题
假设数字
x
x
x 放在了
x
x
x
当前数字为
z
z
z 小于
x
x
x
那么有可能会有的最坏情况有两种
z
×
x
≤
z
×
(
x
−
1
)
+
2025
z \times x \le z \times (x - 1) + 2025
z×x≤z×(x−1)+2025
由于
z
z
z 一定小于
2025
2025
2025 ,所以一定合法
对于
z
×
x
≤
(
z
−
1
)
×
(
x
−
1
)
+
2025
z \times x \le (z - 1) \times (x - 1) + 2025
z×x≤(z−1)×(x−1)+2025
可以发现
对于如果存在
z
×
x
≤
(
z
−
1
)
×
(
x
−
1
)
+
2025
z \times x \le (z - 1) \times (x - 1) + 2025
z×x≤(z−1)×(x−1)+2025 的 x
一定会提前被
x
×
x
≤
(
x
−
1
)
×
(
x
−
1
)
+
2025
x \times x \le (x - 1) \times (x - 1) + 2025
x×x≤(x−1)×(x−1)+2025 给拦截
所以 对于不满足上面条件的事情而言
他会固定位置
否则一定可以交换前面的
所以找到个数即可
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout);
const int mod = 1e9 + 7;
int main(){
cin.tie(nullptr) -> ios::sync_with_stdio(false);
const int n = 2025;
vector<LL> dp(n + 1);
dp[0] = 1,dp[1] = 1;
for(int i = 2;i <= 2025; i ++){
if(i * i <= (i - 1) * (i - 1) + 2025)
dp[i] = (dp[i - 1] + dp[i - 2]) % mod;
else {
dp[i] = dp[i - 1];
}
}
cout << dp[n] <<"\n";
return 0;
}
C
对于数字 x x x 满足 [ − ( x − 1 ) ] + [ − ( x − 2 ) ] + . . . + 0 + 1 + 2 + . . . + x = x [-(x-1)] + [-(x - 2)] +... + 0 + 1 + 2 +... +x = x [−(x−1)]+[−(x−2)]+...+0+1+2+...+x=x
所以对于稍微大一点的x均满足
对于数字 1 1 1 而言,他死了
对于数字 2 2 2 而言, − 1 + 0 + 1 + 2 -1 + 0 + 1 + 2 −1+0+1+2 可以
所以特判 1 1 1 即可
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout);
int main(){
cin.tie(nullptr) -> ios::sync_with_stdio(false);
int n,ans = 0;
cin >> n;
for(int i = 1;i <= n; i ++){
int x;
cin >> x;
ans += (x != 1);
}
cout << ans <<"\n";
return 0;
}
D
显然
要么会变成定值
要么 会变成几个数一直在那循环
比方说 1 2 2?
1 2 2
2 1 1
怎么好像不循环
试一下先
打表可得
// 表
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout);
int main(){
cin.tie(nullptr) -> ios::sync_with_stdio(false);
for(int i = 1;i <= 100;i ++){
for(int j = 1;j <= 100;j ++){
for(int k = 1; k <= 100;k ++){
int a = i,b = j,c = k;
int cnt = 0;
while(true){
cnt ++;
int aa = b + c >> 1,bb = a + c >> 1,cc = a + b >> 1;
if(a == aa && b == bb && c == cc)break;
a = aa,b = bb,c = cc;
if(cnt > 10){
cout << i <<" "<<j <<" "<<k <<"\n";
return 0;
}
}
}
}
}
return 0;
}
不存在次数多的
所以有
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout);
int main(){
cin.tie(nullptr) -> ios::sync_with_stdio(false);
int T;
cin >> T;
while(T--){
int a,b,c,k;
cin >> a >> b >> c >> k;
while(k --){
int aa = b + c >> 1,bb = a + c >> 1,cc = a + b >> 1;
if(a == aa && b == bb && c == cc)break;
a = aa,b = bb,c = cc;
}
cout << a <<" "<< b <<" "<<c <<"\n";
}
return 0;
}
E
首先有 一定按顺序排
如果不按顺序一定会使得贡献变大
所以其实就是相邻的数做一下
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout);
int main(){
cin.tie(nullptr) -> ios::sync_with_stdio(false);
int n,m;
cin >> n >> m;
vector<int> a(n + 1);
for(int i = 1;i <= n ;i ++){
cin >> a[i];
}
sort(a.begin(),a.end());
LL ans = 1e18;
vector<LL> b(n);
for(int i = 1;i < n; i ++){
b[i] = 1LL * a[i + 1] * a[i + 1] - 1LL * a[i] * a[i];
b[i] += b[i - 1];
}
for(int i = m - 1;i < n ;i ++){
ans = min(ans,b[i] - b[i - m + 1]);
}
cout << ans <<"\n";
return 0;
}
F
差一点以为斯坦树板子了
2 × n 2 \times n 2×n 的河床
所以直接大力跑 d p dp dp 连接前面是对的
那么前面有几种情况
前面如果是和我同一行,那么我就直接连
否则把我变成一列全是1的形态
然后去做连接
所以简单离散化一下然后直接跑
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout);
int main(){
// fre("");
cin.tie(nullptr) -> ios::sync_with_stdio(false);
string a,b;
cin >> a >> b;
vector<pair<int,int>> v;
for(int i = 0; i < a.size();i ++){
int cnt = (a[i] == '#') * 2 + (b[i] == '#');
if(cnt){
v.push_back({cnt,i});
}
}
int ans = 0;
for(int i = 1;i < v.size();i ++){
if(v[i].first & v[i - 1].first){
ans += v[i].second - v[i - 1].second - 1;
}else {
v[i].first |= 3;
ans += v[i].second - v[i - 1].second;
}
}
cout << ans <<"\n";
return 0;
}
G
树上背包…
朴素的是 n 3 n^3 n3 的,然后可以考虑 b i t s e t bitset bitset 加速一下,复杂度会优化成 n 3 w \frac{n^3}{w} wn3,其中 w = 64 w = 64 w=64。
当然也可以手撕一个多项式卷积,可以将复杂度优化到 n 2 log 2 n n^2\log_2n n2log2n。
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout);
const int N = 1e3 + 10;
int a[N];
vector<int> node[N];
bitset<N> dp[N],temp;
void dfs(int u,int fa){
dp[u][0] = 1;
int son = 0;
for(int x:node[u])if(x != fa){
dfs(x,u);
son ++;
temp = dp[u];
// 这个位置可以写成f * g 的多项式卷积,掏任意一个卷积模板都可以使得他优化成nlog
for(int i = 1;i <= a[x];i ++){
if(dp[x][i]){
dp[u] |= temp << i;
}
}
}
if(son == 0)dp[u][a[u]] = 1;
for(int i = a[u] + 1;i < N ;i ++){
dp[u][i] = 0;
}
}
int main(){
cin.tie(nullptr) -> ios::sync_with_stdio(false);
int n;
cin >> n;
for(int i = 1;i <= n ;i ++){
cin >> a[i];
}
for(int i = 1;i < n ;i ++){
int x,y;
cin >> x >> y;
node[x].push_back(y);
node[y].push_back(x);
}
dfs(1,0);
int ans = 0;
for(int i = 1;i < N ;i ++){
if(dp[1][i]){
ans = i;
}
}
cout << ans <<"\n";
return 0;
}
H
需要特殊处理一下 前缀
枚举段,然后枚举前面的符号,去计算贡献?
怎么前面一加,后面一减就抵消了
所以只有前缀需要算
那么对于前缀从一个位置断开之后,后面计算出现次数即可
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout);
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
LL p3[N];
int main(){
cin.tie(nullptr) -> ios::sync_with_stdio(false);
int n;
cin >> n;
p3[0] = 1;;
for(int i = 1;i <= n ;i ++){
p3[i] = p3[i - 1] * 3 % mod;
}
LL ans = 0,sum = 0;
for(int i = 1;i <= n ;i ++){
int x;
cin >> x;
sum ^= x;
// 后面一个符号一定要选择 + 或者 -,除非是最后一个
// 其他可以选3种
if(i != n){
ans += (sum * 2) * p3[n - i - 1] % mod;
}else {
ans += sum;
}
ans %= mod;
}
cout << ans <<"\n";
return 0;
}