「CF1301C Ayoub's function」

本题结论题,所以就不放前置芝士了.

具体做法

先将最终的答案分为两部分,区间(开始于结束为止不同)和点,点的个数非常显然就是M,于是要计算区间的个数,可以发现如果直接计算有多少合法区间很麻烦,所以用总共的区间数(frac{N*(N-1)}{2}),减去没有的部分,可以发现这M个1可以将这个区间分成M+1段0(长度可以为0),两段之间有1的0之间不会相互影响,所以没有的部分就是每一段0中的区间个数之和,对于每一段0中的区间个数,设一个函数(f(x)=frac{x*(x-1)}{2}),可以发现这是一个二次函数,然后经过感谢理解,当每一段长度尽可能相等时最终的没有0的区间个数才是最少,所以可以计算出两个数(num1)(num2),(num1)为长度为(lfloor frac{N-M}{M+1} floor+1)的连续0的段数,(num2)为长度为(lfloor frac{N-M}{M+1} floor)的连续0的段数,然后将长度带入函数,再乘上相应的区间数,在总区间数中减去,就可以知道至少含有一个1的区间个数了,最终答案只要再加上一个M就好了.

代码

#include<bits/stdc++.h>
#define REP(i,first,last) for(int i=first;i<=last;++i)
#define DOW(i,first,last) for(int i=first;i>=last;--i)
using namespace std;
long long N,M;
int T;
void work()
{
	scanf("%lld%lld",&N,&M);
	long long len=(N-M)/(M+1);//计算出长度
	long long num1=(N-M-len*(M+1));//因为这个长度是向下取整的随意可能有剩余,而长度为len+1的个数自然就是剩余的0的个数了
	long long num2=M+1-num1;//因为总共有M+1段
	long long answer=N*(N-1)-len*(len+1)*num1-len*(len-1)*num2;//计算
	answer/=2;//前面没有除二
	printf("%lld
",answer+M);//最后答案加上M之后输出
}
int main()
{
	scanf("%d",&T);
	REP(i,1,T)
	work();
	return 0;
}
原文地址:https://www.cnblogs.com/Sxy_Limit/p/12307505.html