https://vjudge.net/problem/CodeForces-1301C
题目大意:对于一个长度为
n的
01串
s,规定
f(s)=∑l=1n∑r=lnval(l,r),如果
s[l……r]中至少有
1个
1,那么
val(l,r)=1,否则
val(l,r)=0。也就是说
f(s)整数对
(l,r)的个数,且
s[l……r]中至少有
1个
1。现在给定两个数
n、m,表示
s的长度为
n,且
s中
1的个数为
m,问所有符合该情况的
s的
f(s)的最大值。
思路:根据容斥原理,答案就等于:整数对
(l,r)的总数量
−s[l……r]中不包含
1的整数对
(l,r)的数量。整数对
(l,r)的总数量其实就等于
n∗(n+1)/2,且如果区间
[l,r]内不包含
1的话,那么这个区间包含了
(r−l+1)∗(r−l+2)/2种选择(与区间长度有关),那么我们可以根据
1的个数来把
s划分成几个不同的部分,这样答案就比较好计算了。接下来我们看一下怎么划分
s使得
f(s)最大,根据上面的推导,由于第一部分是一个定值,要使
f(s)最大,就要使第二部分的值最小,不难想(猜)到用这
m个
1把
n−m个
0尽可能均匀的分成
m+1份时,第二部分的取值最小。设
res1=(n−m)/(m+1),res2=(n−m)%(m+1),那么有
res2份区间长度为
res1+1的,还有
m+1−res2份区间长度为
res1的,那么答案就出来了,复杂度
O(1)。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
ll cal(ll n)
{
return n*(n+1)>>1;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
ll n,m;
scanf("%lld%lld",&n,&m);
ll res1=(n-m)/(m+1);
ll res2=(n-m)%(m+1);
ll ans=cal(n);
ans-=cal(res1+1)*res2+cal(res1)*(m+1-res2);
printf("%lld\n",ans);
}
return 0;
}