CF1301C Ayoub's function

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

具体做法

先将最终的答案分为两部分,区间(开始于结束为止不同)和点,点的个数非常显然就是M,于是要计算区间的个数,可以发现如果直接计算有多少合法区间很麻烦,所以用总共的区间数 N ∗ ( N − 1 ) 2 \frac{N*(N-1)}{2} 2N(N1),减去没有的部分,可以发现这M个1可以将这个区间分成M+1段0(长度可以为0),两段之间有1的0之间不会相互影响,所以没有的部分就是每一段0中的区间个数之和,对于每一段0中的区间个数,设一个函数 f ( x ) = x ∗ ( x − 1 ) 2 f(x)=\frac{x*(x-1)}{2} f(x)=2x(x1),可以发现这是一个二次函数,然后经过感谢理解,当每一段长度尽可能相等时最终的没有0的区间个数才是最少,所以可以计算出两个数 n u m 1 num1 num1 n u m 2 num2 num2, n u m 1 num1 num1为长度为 ⌊ N − M M + 1 ⌋ + 1 \lfloor \frac{N-M}{M+1} \rfloor+1 M+1NM+1的连续0的段数, n u m 2 num2 num2为长度为 ⌊ N − M M + 1 ⌋ \lfloor \frac{N-M}{M+1} \rfloor M+1NM的连续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\n",answer+M);//最后答案加上M之后输出
}
int main()
{
	scanf("%d",&T);
	REP(i,1,T)
	work();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值