codeforces 1301C Ayoub's function 贪心+容斥原理

https://vjudge.net/problem/CodeForces-1301C

题目大意:对于一个长度为 n n 01 01 s s ,规定 f ( s ) = l = 1 n r = l n v a l ( l , r ) f(s)=\sum_{l=1}^n\sum_{r=l}^n val(l,r) ,如果 s [ l r ] s[l……r] 中至少有 1 1 1 1 ,那么 v a l ( l , r ) = 1 val(l,r)=1 ,否则 v a l ( l , r ) = 0 val(l,r)=0 。也就是说 f ( s ) f(s) 整数对 ( l , r ) (l,r) 的个数,且 s [ l r ] s[l……r] 中至少有 1 1 1 1 。现在给定两个数 n m n、m ,表示 s s 的长度为 n n ,且 s s 1 1 的个数为 m m ,问所有符合该情况的 s s f ( s ) f(s) 的最大值。

思路:根据容斥原理,答案就等于:整数对 ( l , r ) (l,r) 的总数量 s [ l r ] -s[l……r] 中不包含 1 1 的整数对 ( l , r ) (l,r) 的数量。整数对 ( l , r ) (l,r) 的总数量其实就等于 n ( n + 1 ) / 2 n*(n+1)/2 ,且如果区间 [ l , r ] [l,r] 内不包含 1 1 的话,那么这个区间包含了 ( r l + 1 ) ( r l + 2 ) / 2 (r-l+1)*(r-l+2)/2 种选择(与区间长度有关),那么我们可以根据 1 1 的个数来把 s s 划分成几个不同的部分,这样答案就比较好计算了。接下来我们看一下怎么划分 s s 使得 f ( s ) f(s) 最大,根据上面的推导,由于第一部分是一个定值,要使 f ( s ) f(s) 最大,就要使第二部分的值最小,不难想(猜)到用这 m m 1 1 n m n-m 0 0 尽可能均匀的分成 m + 1 m+1 份时,第二部分的取值最小。设 r e s 1 = ( n m ) / ( m + 1 ) r e s 2 = ( n m ) % ( m + 1 ) res1=(n-m)/(m+1),res2=(n-m)\%(m+1) ,那么有 r e s 2 res2 份区间长度为 r e s 1 + 1 res1+1 的,还有 m + 1 r e s 2 m+1-res2 份区间长度为 r e s 1 res1 的,那么答案就出来了,复杂度 O ( 1 ) 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;
}

发布了677 篇原创文章 · 获赞 30 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/xiji333/article/details/104314236