专栏文章
题解:P13009 【MX-X13-T4】「KDOI-12」好胜是人的本能,功利是社会的本性。
P13009题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mip0m14p
- 此快照首次捕获于
- 2025/12/03 04:12 3 个月前
- 此快照最后确认于
- 2025/12/03 04:12 3 个月前
P13009
特殊性质启发我们应该考虑分类做。
-
当 时:此时 ,则 。因此 的值会越来越接近 , 会越来越小。而 只变换一次便是最大的情况( 例外,需特判)。
-
当 时:
此时 ,则 。因此 经过变换后会越来越大,直到一个定值,记做了 次后进入循环。直接暴力枚举算出变换次数即可,复杂度类似于数论分块(?。发现一个性质,在这之后变换 次 都是最大值(对后面有用)。
处理完以上内容后,发现情况 的相邻数字可以合在一起,操作次数为 ;情况 的相邻数字可以合在一起,操作次数为 (因为比最大值小的数可以用上面的性质补平成最大值);对于 的情况,无论分在哪边都可以,可以直接无视。
这样,每个块就被压缩成单点操作,也就是情况 和情况 交替。发现若全部都是大于 的,可以把 全推了,然后再一个一个推,最小次数即为 。但是可能会有刚开始就进入循环的数字,那么他们要不就不推(分成散的),要不就当成 来做(性质),发现贡献是一样的。设 块的数量为 (头尾 块不用算),则最小次数为 。
AC Code
CPP#include <bits/stdc++.h>
#define int long long
using namespace std;
int ans , x;
int vis[100005];
signed main ()
{
ios::sync_with_stdio (0) , cin.tie (0) , cout.tie (0);
int T;
cin >> T;
while (T --)
{
int n , m;
cin >> n >> m;
ans = 0;
int sq = sqrt (m);
for (int i = 1;i <= n;i ++)
{
cin >> x;
if (x == m / x) vis[i] = -1 , ans += x;
else if (x <= sq) vis[i] = 1 , ans += m / x;
else
{
vis[i] = 0;
while (m / (m / x) != x) x = m / (m / x) , vis[i] += 2;
ans += x;
}
}
vis[n + 1] = 0;
int mx = 0 , l = 0;
int cnt = 0;
vector <int> s;
int p = 1;
while (vis[p] == -1)p ++;
if (vis[p] == 1) s.push_back (1);
for (int i = 1;i <= n;i ++)
{
if (vis[i] % 2 == 0 && !l)
l = i , mx = vis[i];
else if (vis[i] % 2 == 0) mx = max (mx , vis[i]);
else if (vis[i] == 1)
{
if (l) s.push_back (mx) , s.push_back (1);
mx = 0 , l = 0;
}
}
if (l) s.push_back (mx);
if (s.size () == 0)
{
cout << ans << ' ' << 0 << '\n';
continue;
}
int cnt0 = 0;
for (int num : s)
{
if (num > 1) cnt += num - 1 , num = 1;
else if (num == 0) cnt0 ++;
}
if (s[0] == 0) cnt0 --;
if (s.size () && s[s.size () - 1] == 0) cnt0 --;
cout << ans << ' ' << cnt + 1 + cnt0 << '\n';
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...