「杂题乱刷2」CF1301C

怎么没有二分的题解啊,写一篇。

题目链接

CF1301C Ayoub's function

解题思路

发现我们可以将问题转化成将 \(n - m\)\(1\) 分成 \(m\) 份,设第 \(i\) 份的数字之和为 \(sum_i\),则这样的分配方案的贡献为 \(\frac{n \times (n+1)}{2} - \sum_{i=1}^{n} sum_i^2\)

容易发现要使得这样的贡献最小,你选择的不同的每份数字和的个数一定不超过 \(2\)

因此你可以通过简单的数学来计算出这两种数字的取值,至于两种数字的数量可以直接二分。

单组测试时间复杂度 \(O(\log m)\)

参考代码

#include<bits/stdc++.h>
using namespace std;
//#define map unordered_map
#define re register
#define ll long long
#define forl(i,a,b) for(re ll i=a;i<=b;i++)
#define forr(i,a,b) for(re ll i=a;i>=b;i--)
#define forll(i,a,b,c) for(re ll i=a;i<=b;i+=c)
#define forrr(i,a,b,c) for(re ll i=a;i>=b;i-=c)
#define pii pair<ll,ll>
#define mid ((l+r)>>1)
#define lowbit(x) (x&-x)
#define pb push_back
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define endl '\n'
#define QwQ return 0;
ll _t_;
void _clear(){}
ll n,m;
ll ans;
void solve()
{
	ans=0;
	_clear();
	cin>>n>>m;
	if(m==0)
	{
		cout<<0<<endl;
		return ;
	}
	if(n==m)
	{
		cout<<(n+1)*n/2<<endl;
		return ;
	}
	ll last=n-m;
	ll num=last/(m+1);
//	cout<<"number:"<<num<<endl;
	ll L=0,R=m+1;
	while(L<R)
	{
		ll Mid=(L+R+1)/2;
		if(Mid*num<=last)
			L=Mid;
		else
			R=Mid-1;
	}
	ll _0=L,_1=last-L*num;
	_0-=_1;
//	cout<<L<<":"<<_0<<' '<<_1<<endl;
	cout<<(n+1)*n/2 - (_0*(num+1)*num/2 + _1*(num+2)*(num+1)/2)<<endl;
}
int main()
{
	IOS;
	_t_=1;
 	cin>>_t_;
	while(_t_--)
		solve();
	QwQ;
}
posted @ 2024-09-06 18:27  wangmarui  阅读(6)  评论(0编辑  收藏  举报