牛客小白月赛76 https://ac.nowcoder.com/acm/contest/60393

F. Kevin的矩阵

1.题意

给出n个数字的数字序列组成一个矩阵,m表示矩阵初始的列数,这n个数从左至右从上至下排列在矩阵中。要求进行若干次操作,使得矩阵的某一列的值全部为k
可以执行的操作有:
1.将矩阵的列数加1或者减1
2.改变矩阵中某个数的值
一共有t组数据,并且保证所有数据中的n的和小于2e5

2.思路

不论数据怎样,每组样例中所进行的操作数都不多于2 次操作
1.初始的列数m小于 ,那么可以花费至多 – m次 操作将列数变为 ,然后花费至多 + 1 次操作改变某一列上面的值来保证这一列的值全部为k。假设m为最糟糕的情况,即m = 1,那么总共最多需要 2 次操作。
2.初始的列数m大于 那么直接将某一列中的所有不为k的数都变为k。最多花费 次操作表示即可符合要求,因为m 所以,
所以总操作数永远小于 2

因此可以只对列数 [m – , m+]的区域进行遍历。(如果列数在这个范围之外,那么进行列数变换的操作花费已经大于最糟糕的情况了)

3.代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<iostream>
#include<cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
int a[200010];
int main(){
int t;
cin>>t;
int n,m,k;
while(t--){
int ans = INF;
cin>>n>>m>>k;
for(int i = 1;i<=n;i++){
scanf("%d",&a[i]);
}
int l = m - 2 * sqrt(n) - 5;
l = max(l,1);
int r = m + 2 * sqrt(n) + 5;
r = min(n,r);
for(int c = l;c<=r;c++){
for(int i = 1;i<=c;i++){
int num = a[i];
int cnt = abs(m - c);
for(int j = i;j <= n;j+=c){
if(a[j] != k){
cnt++;
}
}
ans = min(ans,cnt);
}
}
cout<<ans<<endl;
}
return 0;
}

G.Kevin逛超市

1.题意

在n个物品中有1个是“有问题的”,为了找到这个物品,依次循环进行以下操作:
选出这些物品当中的前 (n+1)/2 个数进行一次检测,如果检测到了“目标物品”,就选择这组物品重复操作,如果没有检测到,就选择另外的 n/2 个物品重复操作
直到待检测的物品只有一个并且经过检测后确认该物品是“有问题的”,停止检测。
可以得出总的期望次数 ,要求计算 mod 998244353 的结果。
输入一个数t代表一共有t组样例,每组样例输入一个数n
(t <= 2* n<=)
输出每组样例的期望次数
每组样例输出一个数代表结果

2.思路

  1. 期望$dp$,容易得出$dp[i] = 1 + dp[i/2] + dp[(i+1)/2]$ 这样可以通过dfs来在logn的规模下进行求解。
  2. 通过map记录已经搜索的数据,实现记忆化搜索
  3. 需要特判$dp[1]$和$dp[2]$ (dp[1]需要特判自不必多说,dp[2]需要特判在于按照题目规则 dp[2] = 而按照递归方程得出的$dp[2] = 1 + dp[1] + dp[1] = 2 $不符合题意)

3.代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 998244353;
unordered_map<int, int> mp;
int qp(int a, int k)//快速幂 quick pow
{
int res = 1;
while (k)
{
if (k & 1) res = (LL) res * a % mod;
a = (LL) a * a % mod;
k >>= 1;
}

return res;
}

int dfs(int l, int r)
{
int len = r - l + 1, mid = l + r >> 1;
if (len == 1) return 1;
if (mp[len] != 0) return mp[len];

int &val = mp[len];
if (mid - l + 1 == 1) val = dfs(l, mid);
else val = dfs(l, mid) + mid - l + 1;
val %= mod;
val = (val + dfs(mid + 1, r)) % mod;
val = (val + r - mid) % mod;
return val;
}

void solve()
{
int n;
cin >> n;
cout << (LL)dfs(1, n) * qp(n, mod - 2) % mod << "\n";
}

int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);

int T;
cin >> T;

while (T -- ) solve();

return 0;
}

4.节时

本题对时间要求不严格,但如果需要节时,可以考虑如下:
使用二维数组mp[70][2]来代替map进行记录,其中mp[i][j]中的i代表进行第i次二分后的两个数,j如果为0就是较小者,为1就是较大者