题解:P17299 [ICPC 2026 Xi'an I] Split Sticks
lailai0916 · · 题解
题意简述
给定一排木棍。 每次选择一根木棍,把它切成两个整数长度的部分, 再分别并入左右相邻木棍。 位于端点时,没有相邻木棍的一段独立保留。
求最少需要多少次操作,才能使剩余木棍全部等长。
解题思路
把所有木棍首尾相接,放在线段
对一根内部木棍操作时, 它两侧的相邻分界点会合并为两点之间的任意整数点。 也就是说,两个相邻的内部分界点减少为一个。
对首端木棍操作时,
可以把最左侧的内部分界点移动到它与
设最后剩下
其中
若只使用内部操作, 每个最终分界点都由一段非空、连续的初始内部分界点合并而成。 一组分界点可以合并到其最左与最右位置之间的任意整数点。
考虑相邻的最终分界点
反过来,若对每个
上述条件可以贪心检查。
从左到右处理区间
还需处理首尾两个最终分界点。
若
初始有
所以固定
其中
从
设
参考代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=1000005;
ll a[N];
bool check(int n,int m,ll x)
{
if(m<=2)return 1;
int need=1;
for(int i=1;i<n&&need<=m-2;i++)
{
if(a[i]<need*x)continue;
if(a[i+1]>(need+1)*x)return 0;
need++;
}
return need==m-1;
}
void solve()
{
int n;
cin>>n;
a[0]=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
a[i]+=a[i-1];
}
int ans=n-1;
for(int i=0;i<ans;i++)
{
int m=n-i;
if(a[n]%m)continue;
ll x=a[n]/m;
int res=i+(a[1]>x)+(a[n]-a[n-1]>x);
if(res<ans&&check(n,m,x))ans=res;
}
cout<<ans<<'\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin>>T;
while(T--)solve();
return 0;
}